diff --git a/apps/forms-flow-ai/README.md b/apps/forms-flow-ai/README.md
index 4819a120..2c684f3d 100644
--- a/apps/forms-flow-ai/README.md
+++ b/apps/forms-flow-ai/README.md
@@ -66,7 +66,7 @@ The following files are slated to be removed because we can leverage the open so
### **Required files:**
-- `pom-docker.xml`
+- `pom-docker.xml` (renamed pom.xml with v5.1.0 upgrade)
- Needed for redis dependency; otherwise, the dependencies are largely identical to open source.
- `src/main/resources/application.yaml`
- Useful to have application.yaml in this repo as it is used for customizing camunda.
@@ -186,7 +186,7 @@ Upon a new release of open source, care should be taken to keep all the files al
- All files under `src` folder.
*forms-flow-bpm*
-- `pom-docker.xml`
+- `pom-docker.xml` (renamed pom.xml with v5.1.0 upgrade)
- Java dependencies' versions may be different.
- `application.yaml`
- should be checked for updates as well but not all changes are applicable to service BC. Changes should be done on a case by case basis based on Changelog documentation.
diff --git a/apps/forms-flow-ai/forms-flow-bpm/Dockerfile b/apps/forms-flow-ai/forms-flow-bpm/Dockerfile
index acb76076..83111883 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/Dockerfile
+++ b/apps/forms-flow-ai/forms-flow-bpm/Dockerfile
@@ -1,38 +1,47 @@
# Modified by Yichun Zhao and Walter Moar
# Maven build
-FROM artifacts.developer.gov.bc.ca/docker-remote/maven:3.6.1-jdk-11-slim AS MAVEN_TOOL_CHAIN
+# FROM artifacts.developer.gov.bc.ca/docker-remote/maven:3.8.1-openjdk-17-slim AS MAVEN_TOOL_CHAIN
+FROM maven:3.8.1-openjdk-17-slim AS MAVEN_TOOL_CHAIN
RUN apt-get update \
&& apt-get install -y git
RUN git clone -b ${FORMIO_SOURCE_REPO_BRANCH} ${FORMIO_SOURCE_REPO_URL} /bpm/
-#RUN cp /bpm/forms-flow-bpm/pom-docker.xml /tmp/pom.xml
-RUN cp /bpm/forms-flow-bpm/settings-docker.xml /usr/share/maven/ref/
-COPY ./pom-docker.xml /tmp/pom.xml
+# RUN cp /bpm/forms-flow-bpm/pom.xml /tmp/pom.xml
+# RUN cp /bpm/forms-flow-bpm/settings-docker.xml /usr/share/maven/ref/
+# COPY ./pom.xml /tmp/pom.xml
+# COPY ./pom-default.xml /tmp/pom-default.xml
+COPY ./pom*.xml /tmp/
+COPY ./settings-docker.xml /usr/share/maven/ref/
# COPY ./settings-docker.xml /usr/share/maven/ref/
-WORKDIR /tmp/
+WORKDIR /tmp
# This allows Docker to cache most of the maven dependencies
RUN mvn -s /usr/share/maven/ref/settings-docker.xml dependency:resolve-plugins dependency:resolve dependency:go-offline -B
-RUN cp -r /bpm/forms-flow-bpm/src/ /tmp/src/
+RUN cp -rf /bpm/forms-flow-bpm/src/ /tmp/src/
-ARG CUSTOM_SRC_DIR=src/
+
+
+ARG CUSTOM_SRC_DIR=src
# Override these files they have custom changes in the sbc_divapps directory
COPY ./${CUSTOM_SRC_DIR}/ /tmp/${CUSTOM_SRC_DIR}/
-RUN mvn -s /usr/share/maven/ref/settings-docker.xml package
+RUN mvn -s /usr/share/maven/ref/settings-docker.xml package -P default
+# RUN mvn -s /usr/share/maven/ref/settings-docker.xml package
+
# Final custom slim java image (for apk command see jdk-11.0.3_7-alpine-slim)
-FROM artifacts.developer.gov.bc.ca/docker-remote/adoptopenjdk/openjdk11:jdk-11.0.3_7-alpine
+# FROM artifacts.developer.gov.bc.ca/docker-remote/openjdk:17-jdk-alpine
+FROM openjdk:17-jdk-alpine
-ENV JAVA_VERSION jdk-11.0.3+7
-ENV JAVA_HOME=/opt/java/openjdk \
- PATH="/opt/java/openjdk/bin:$PATH"
+ENV JAVA_VERSION=17-ea+14
+ENV JAVA_HOME=/opt/java/openjdk-17 \
+ PATH="/opt/java/openjdk-17/bin:$PATH"
EXPOSE 8080
# OpenShift has /app in the image, but it's missing when doing local development - Create it when missing
@@ -43,4 +52,5 @@ COPY --from=MAVEN_TOOL_CHAIN /tmp/target/forms-flow-bpm.jar ./app
RUN chmod a+rwx -R /app
WORKDIR /app
VOLUME /tmp
-ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/forms-flow-bpm.jar"]
\ No newline at end of file
+ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/forms-flow-bpm.jar"]
+# ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom", "-Dpolyglot.js.nashorn-compat=true", "-Dpolyglot.engine.WarnInterpreterOnly=false", "-jar","/app/forms-flow-bpm.jar"]
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-bpm/pom-default.xml b/apps/forms-flow-ai/forms-flow-bpm/pom-default.xml
new file mode 100644
index 00000000..f22747cc
--- /dev/null
+++ b/apps/forms-flow-ai/forms-flow-bpm/pom-default.xml
@@ -0,0 +1,18 @@
+
+
+ 4.0.0
+
+
+ org.camunda.bpm.extension
+ formsflow-bpm
+ 5.1.0
+ pom.xml
+
+
+ default
+
+
+
+
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-bpm/pom-docker.xml b/apps/forms-flow-ai/forms-flow-bpm/pom.xml
similarity index 78%
rename from apps/forms-flow-ai/forms-flow-bpm/pom-docker.xml
rename to apps/forms-flow-ai/forms-flow-bpm/pom.xml
index 7392e00b..406af905 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/pom-docker.xml
+++ b/apps/forms-flow-ai/forms-flow-bpm/pom.xml
@@ -4,31 +4,33 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
- org.camunda.bpm
- extension
- 2.0.0
+ org.camunda.bpm.extension
+ formsflow-bpm
+ 5.1.0
+ pom
Forms flow BPM Extension
Forms flow BPM Extension
- 11
- 11
- 11
+ 17
+ 17
+ 17
UTF-8
${encoding}
${encoding}
false
- 7.15.0
- 7.15.0
- 1.2.2
- 1.2.0
- 2.6.4
- 2.6.4
- 2.13.3
- 2.2.3
+ 2.2.3
+ 7.17.0
+ 1.5.0
+ 1.3.0
+ 2.6.6
+ 2.6.6
+ 2.14.0
+
@@ -36,7 +38,7 @@
com.h2database
h2
- 2.0.206
+ 2.0.206
org.camunda.bpm
@@ -71,13 +73,18 @@
org.camunda.bpm.springboot
camunda-bpm-spring-boot-starter-webapp
- ${version.camundaSpringBoot}
+ ${version.camunda}
org.camunda.bpm.springboot
camunda-bpm-spring-boot-starter-rest
- ${version.camundaSpringBoot}
+ ${version.camunda}
+
+
+
+ org.springframework.boot
+ spring-boot-starter-hateoas
@@ -116,7 +123,7 @@
spring-security-oauth2-jose
-
+
org.camunda.bpm.extension
camunda-bpm-identity-keycloak
@@ -179,8 +186,8 @@
org.postgresql
postgresql
-
- 42.2.5
+
+ 42.4.3
@@ -249,7 +256,7 @@
org.jsoup
jsoup
- 1.13.1
+ 1.15.3
@@ -290,15 +297,33 @@
org.springframework
spring-websocket
- 5.3.4
+ 5.3.20
org.springframework
spring-messaging
- 5.3.4
+ 5.3.20
+
+
+
+ org.graalvm.js
+ js-scriptengine
+ 22.1.0.1
+
+ org.graalvm.js
+ js
+ 22.1.0.1
+
+
+
+ org.springframework.boot
+ spring-boot-starter-jersey
+
+
+
org.springframework.boot
spring-boot-starter-data-redis-reactive
@@ -325,12 +350,12 @@
org.apache.maven.plugins
maven-surefire-plugin
- 3.0.0-M5
+ 3.0.0-M7
org.jacoco
jacoco-maven-plugin
- 0.8.7
+ 0.8.8
target/jacoco-ut
@@ -349,6 +374,18 @@
org/camunda/bpm/extension/commons/connector/auth/FormioContext.class
org/camunda/bpm/extension/commons/connector/*.class
org/camunda/bpm/extension/CamundaApplication.class
+ org/camunda/bpm/extension/commons/exceptions/*.class
+ org/camunda/bpm/extension/commons/utils/*.class
+ org/camunda/bpm/extension/hooks/controllers/mapper/*.class
+ org/camunda/bpm/extension/hooks/exceptions/*.class
+ org/camunda/bpm/extension/hooks/listeners/execution/FormAccessTokenCacheListener.class
+ org/camunda/bpm/extension/hooks/rest/exception/*.class
+ org/camunda/bpm/extension/commons/exceptions/*.class
+ org/camunda/bpm/extension/commons/config/*.class
+ org/camunda/bpm/extension/hooks/rest/constant/*.class
+ org/camunda/bpm/extension/hooks/services/IMessageEvent.class
+ org/camunda/bpm/extension/hooks/rest/dto/*.class
+ org/camunda/bpm/extension/hooks/rest/impl/*.class
@@ -365,6 +402,7 @@
spring-boot-maven-plugin
${version.springBoot}
+ org.camunda.bpm.extension.CamundaApplication
ZIP
@@ -389,37 +427,13 @@
default
+
+ pom-default.xml
+
true
-
-
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 3.0.0-M5
-
-
- org.jacoco
- jacoco-maven-plugin
- 0.8.7
-
- target/jacoco-ut
-
-
-
-
- prepare-agent
- report
-
-
-
-
-
-
-
-
+
-
+
+
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-bpm/settings-docker.xml b/apps/forms-flow-ai/forms-flow-bpm/settings-docker.xml
new file mode 100644
index 00000000..f0a1a600
--- /dev/null
+++ b/apps/forms-flow-ai/forms-flow-bpm/settings-docker.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+ defaultProfile
+
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/connector/support/ApplicationAccessHandler.java b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/connector/support/ApplicationAccessHandler.java
index 07f08630..cfc9e0ca 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/connector/support/ApplicationAccessHandler.java
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/connector/support/ApplicationAccessHandler.java
@@ -1,6 +1,8 @@
package org.camunda.bpm.extension.commons.connector.support;
import com.google.gson.JsonObject;
+import org.camunda.bpm.extension.commons.ro.req.IRequest;
+import org.camunda.bpm.extension.commons.ro.res.IResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -8,46 +10,61 @@
import org.springframework.http.*;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.stereotype.Service;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
-import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
+import java.util.Map;
+import static org.springframework.security.oauth2.client.web.reactive.function.client.ServerOAuth2AuthorizedClientExchangeFilterFunction.clientRegistrationId;
/**
* This class serves as gateway for all application service interactions.
- * This customization exists because the authentication mechanisms has changed between
- * forsmflow open source and service bc's implementation. Once Service BC's authentication
- * mechanisms are updated, this file can be removed.
*
* @author sumathi.thirumani@aot-technologies.com
*/
@Service("applicationAccessHandler")
-public class ApplicationAccessHandler implements IAccessHandler {
+public class ApplicationAccessHandler extends AbstractAccessHandler {
private final Logger LOGGER = LoggerFactory.getLogger(ApplicationAccessHandler.class);
-
+
@Autowired
private WebClient unAuthenticatedWebClient;
@Autowired
private OAuth2RestTemplate oAuth2RestTemplate;
-
public ResponseEntity exchange(String url, HttpMethod method, String payload) {
payload = (payload == null) ? new JsonObject().toString() : payload;
- Mono> entityMono = unAuthenticatedWebClient.method(method).uri(url)
+ ResponseEntity response = unAuthenticatedWebClient.method(method).uri(url)
.accept(MediaType.APPLICATION_JSON)
.headers(httpHeaders -> httpHeaders.setBearerAuth(oAuth2RestTemplate.getAccessToken().getValue()))
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.body(Mono.just(payload), String.class)
.retrieve()
- .toEntity(String.class);
+ .toEntity(String.class)
+ .block();
- ResponseEntity response = entityMono.block();
+ // ResponseEntity response = entityMono.block();
return new ResponseEntity<>(response.getBody(), response.getStatusCode());
}
+ public ResponseEntity exchange(String url, HttpMethod method, IRequest payload,
+ Class extends IResponse> responseClazz) {
+
+ ResponseEntity extends IResponse> response = unAuthenticatedWebClient.method(method).uri(url)
+ .accept(MediaType.APPLICATION_JSON)
+ .headers(httpHeaders -> httpHeaders.setBearerAuth(oAuth2RestTemplate.getAccessToken().getValue()))
+ .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
+ .body((payload == null ? BodyInserters.empty() : BodyInserters.fromValue(payload)))
+ .retrieve()
+ .onStatus(HttpStatus::is4xxClientError,
+ clientResponse -> Mono.error(new HttpClientErrorException(HttpStatus.BAD_REQUEST)))
+ .toEntity(responseClazz)
+ .block();
+ return new ResponseEntity<>(response.getBody(), response.getStatusCode());
+ }
}
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/event/CamundaEventListener.java b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/event/CamundaEventListener.java
index 3dfbf08b..ac174547 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/event/CamundaEventListener.java
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/event/CamundaEventListener.java
@@ -8,22 +8,28 @@
import org.camunda.bpm.extension.commons.io.ITaskEvent;
import org.camunda.bpm.extension.commons.io.socket.message.TaskEventMessage;
import org.camunda.bpm.extension.commons.io.socket.message.TaskMessage;
-import org.springframework.beans.BeanUtils;
+import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.event.EventListener;
-
import org.springframework.data.redis.core.StringRedisTemplate;
+//import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Component;
+import javax.annotation.Resource;
import java.util.*;
-
import java.util.logging.Logger;
+import static org.camunda.bpm.extension.commons.utils.VariableConstants.FORM_URL;
+import static org.camunda.bpm.extension.commons.utils.VariableConstants.APPLICATION_STATUS;
+import static org.camunda.bpm.extension.commons.utils.VariableConstants.APPLICATION_ID;
+
/**
- * This class intercepts all camunda task and push socket messages for web tier updates.
+ * Camunda Event Listener.
+ * This class intercepts all camunda task and push socket messages for web tier
+ * updates.
*
* @author sumathi.thirumani@aot-technologies.com
*/
@@ -33,32 +39,57 @@ public class CamundaEventListener implements ITaskEvent {
@Autowired
private StringRedisTemplate stringRedisTemplate;
+ // @Autowired
+ // private SimpMessagingTemplate template;
+
private final Logger LOGGER = Logger.getLogger(CamundaEventListener.class.getName());
@Value("${websocket.messageType}")
private String messageCategory;
-
- @Value("${websocket.messageEvents}")
+
+ @Value("${websocket.messageEvents}")
private String messageEvents;
+ @Value("${websocket.enableRedis}")
+ private boolean redisEnabled;
+
+ @Resource(name = "bpmObjectMapper")
+ private ObjectMapper bpmObjectMapper;
@EventListener
public void onTaskEventListener(DelegateTask taskDelegate) {
- LOGGER.info("Event triggered:"+taskDelegate.getId() +"-"+ taskDelegate.getEventName() + "-"+ taskDelegate.getProcessInstanceId());
+ LOGGER.info("Event triggered:" + taskDelegate.getId() + "-" + taskDelegate.getEventName() + "-"
+ + taskDelegate.getProcessInstanceId());
try {
- if (isRegisteredEvent(taskDelegate.getEventName())) {
- if(isAllowed(EventCategory.TASK_EVENT_DETAILS.name())) {
- this.stringRedisTemplate.convertAndSend(getTopicNameForTaskDetail(), getObjectMapper().writeValueAsString(getTaskMessage(taskDelegate)));
- }
- if(isAllowed(EventCategory.TASK_EVENT.name())) {
- this.stringRedisTemplate.convertAndSend(getTopicNameForTask(), getObjectMapper().writeValueAsString(getTaskEventMessage(taskDelegate)));
- }
- }
+ if (isRegisteredEvent(taskDelegate.getEventName())) {
+ if (isAllowed(EventCategory.TASK_EVENT_DETAILS.name())) {
+ this.stringRedisTemplate.convertAndSend(getTopicNameForTaskDetail(),
+ bpmObjectMapper.writeValueAsString(getTaskMessage(taskDelegate)));
+ }
+ if (isAllowed(EventCategory.TASK_EVENT.name())) {
+ this.stringRedisTemplate.convertAndSend(getTopicNameForTask(),
+ bpmObjectMapper.writeValueAsString(getTaskEventMessage(taskDelegate)));
+ }
+ // convertAndSendMessage(getTopicNameForTaskDetail(),
+ // getTaskMessage(taskDelegate));
+ // if (isAllowed(EventCategory.TASK_EVENT.name())) {
+ // convertAndSendMessage(getTopicNameForTask(),
+ // getTaskEventMessage(taskDelegate));
+ // }
+ }
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
+ private void convertAndSendMessage(String topicName, Object message) throws JsonProcessingException {
+ if (redisEnabled) {
+ this.stringRedisTemplate.convertAndSend(topicName, bpmObjectMapper.writeValueAsString(message));
+ } else {
+ this.stringRedisTemplate.convertAndSend(topicName, bpmObjectMapper.writeValueAsString(message));
+ }
+ }
+
private TaskMessage getTaskMessage(DelegateTask taskDelegate) {
TaskMessage taskObj = new TaskMessage();
BeanUtils.copyProperties(taskDelegate, taskObj);
@@ -73,11 +104,13 @@ private TaskEventMessage getTaskEventMessage(DelegateTask taskDelegate) {
}
private boolean isAllowed(String category) {
- return Arrays.asList(StringUtils.split(messageCategory,",")).contains(category);
+ return Arrays.asList(StringUtils.split(messageCategory, ",")).contains(category);
}
-
- private boolean isRegisteredEvent(String eventName) {
- if("ALL".equalsIgnoreCase(messageEvents)) { return true;}
+
+ private boolean isRegisteredEvent(String eventName) {
+ if ("ALL".equalsIgnoreCase(messageEvents)) {
+ return true;
+ }
return getRegisteredEvents().contains(eventName);
}
@@ -85,14 +118,14 @@ private List getRegisteredEvents() {
if ("DEFAULT".equalsIgnoreCase(messageEvents)) {
return getDefaultRegisteredEvents();
}
- return Arrays.asList(StringUtils.split(messageEvents,","));
+ return Arrays.asList(StringUtils.split(messageEvents, ","));
}
- private Map getVariables(DelegateTask taskDelegate) {
- List configMap =getElements();
- Map variables = new HashMap<>();
- for(String entry : configMap) {
- if(taskDelegate.getVariables().containsKey(entry)) {
+ private Map getVariables(DelegateTask taskDelegate) {
+ List configMap = getElements();
+ Map variables = new HashMap<>();
+ for (String entry : configMap) {
+ if (taskDelegate.getVariables().containsKey(entry)) {
variables.put(entry, taskDelegate.getVariable(entry));
}
}
@@ -100,23 +133,23 @@ private Map getVariables(DelegateTask taskDelegate) {
}
private List getElements() {
- return new ArrayList<>(Arrays. asList("applicationId", "formUrl", "applicationStatus"));
+ return new ArrayList<>(Arrays.asList(APPLICATION_ID, FORM_URL, APPLICATION_STATUS));
}
- private List getDefaultRegisteredEvents() {
+ private List getDefaultRegisteredEvents() {
return Arrays.asList(TaskListener.EVENTNAME_CREATE,
- TaskListener.EVENTNAME_UPDATE,
- TaskListener.EVENTNAME_COMPLETE
- );
+ TaskListener.EVENTNAME_UPDATE,
+ TaskListener.EVENTNAME_COMPLETE);
}
- private ObjectMapper getObjectMapper() {
- return new ObjectMapper();
- }
+ /**
+ * private ObjectMapper getObjectMapper() {
+ * return new ObjectMapper();
+ * }
+ */
enum EventCategory {
- TASK_EVENT,
- TASK_EVENT_DETAILS;
+ TASK_EVENT, TASK_EVENT_DETAILS;
}
}
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/event/TaskEventTopicListener.java b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/event/TaskEventTopicListener.java
index 56b60521..51b2b33d 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/event/TaskEventTopicListener.java
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/event/TaskEventTopicListener.java
@@ -1,6 +1,6 @@
package org.camunda.bpm.extension.commons.io.event;
-import org.camunda.bpm.extension.commons.io.socket.message.service.TaskEventMessageService;
+import org.camunda.bpm.extension.commons.io.message.service.TaskEventMessageService;
import org.camunda.bpm.extension.commons.io.socket.message.TaskMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/socket/service/TaskEventMessageService.java b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/message/service/TaskEventMessageService.java
similarity index 87%
rename from apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/socket/service/TaskEventMessageService.java
rename to apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/message/service/TaskEventMessageService.java
index d0f06b2b..a41dc42d 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/socket/service/TaskEventMessageService.java
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/message/service/TaskEventMessageService.java
@@ -1,4 +1,4 @@
-package org.camunda.bpm.extension.commons.io.socket.message.service;
+package org.camunda.bpm.extension.commons.io.message.service;
import org.camunda.bpm.extension.commons.io.socket.message.TaskMessage;
import org.springframework.beans.factory.annotation.Autowired;
@@ -28,9 +28,8 @@ public void sendMessage(TaskMessage message) {
try {
template.convertAndSend("/topic/task-event", objectMapper.writeValueAsString(message));
} catch (JsonProcessingException e) {
- LOGGER.log(Level.SEVERE,"Exception Occured in preparing message", e);
+ LOGGER.log(Level.SEVERE, "Exception Occured in preparing message", e);
}
}
-
}
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/socket/RedisConfig.java b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/socket/RedisConfig.java
index 38a1478f..f7f09bd5 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/socket/RedisConfig.java
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/socket/RedisConfig.java
@@ -4,6 +4,8 @@
import org.camunda.bpm.extension.commons.io.event.TaskEventTopicListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
@@ -15,6 +17,7 @@
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import java.util.Properties;
+import java.util.logging.Logger;
/**
* Configuration for Message Broker.
@@ -22,29 +25,47 @@
* @author sumathi.thirumani@aot-technologies.com
*/
@Configuration
+@ConditionalOnProperty(prefix = "websocket", name = "enableRedis", havingValue = "true", matchIfMissing = false)
public class RedisConfig implements ITaskEvent {
+ private final Logger LOGGER = Logger.getLogger(RedisConfig.class.getName());
+
@Autowired
private Properties messageBrokerProperties;
+ @Value("${websocket.messageBroker.host}")
+ private String messageBrokerHost;
+ @Value("${websocket.messageBroker.port}")
+ private String messageBrokerPort;
+ @Value("${websocket.messageBroker.passcode}")
+ private String messageBrokerPasscode;
+
@Bean
RedisConnectionFactory redisConnectionFactory() {
- RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(messageBrokerProperties.getProperty("messageBroker.host"),
- Integer.valueOf(messageBrokerProperties.getProperty("messageBroker.port")));
- redisStandaloneConfiguration.setPassword(messageBrokerProperties.getProperty("messageBroker.passcode"));
+ /*
+ * RedisStandaloneConfiguration redisStandaloneConfiguration = new
+ * RedisStandaloneConfiguration(messageBrokerProperties.getProperty(
+ * "messageBroker.host"),
+ * Integer.valueOf(messageBrokerProperties.getProperty("messageBroker.port")));
+ * redisStandaloneConfiguration.setPassword(messageBrokerProperties.getProperty(
+ * "messageBroker.passcode"));
+ */
+
+ RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(messageBrokerHost,
+ Integer.valueOf(messageBrokerPort));
+ redisStandaloneConfiguration.setPassword(messageBrokerPasscode);
return new LettuceConnectionFactory(redisStandaloneConfiguration);
}
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
- @Qualifier("taskMessageListenerAdapter") MessageListenerAdapter taskMessageListenerAdapter) {
+ @Qualifier("taskMessageListenerAdapter") MessageListenerAdapter taskMessageListenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(taskMessageListenerAdapter, new PatternTopic(getTopicNameForTask()));
return container;
}
-
@Bean("taskMessageListenerAdapter")
MessageListenerAdapter chatMessageListenerAdapter(TaskEventTopicListener taskEventTopicListener) {
return new MessageListenerAdapter(taskEventTopicListener, getExecutorName());
@@ -55,7 +76,8 @@ StringRedisTemplate template(RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}
- private String getExecutorName() { return "receiveTaskMessage";}
-
+ private String getExecutorName() {
+ return "receiveTaskMessage";
+ }
}
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/socket/message/TaskEventMessage.java b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/socket/message/TaskEventMessage.java
new file mode 100644
index 00000000..521afccc
--- /dev/null
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/socket/message/TaskEventMessage.java
@@ -0,0 +1,21 @@
+package org.camunda.bpm.extension.commons.io.socket.message;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+import java.io.Serializable;
+
+/**
+ * Task Event Message.
+ * Class for holding TaskEvent data.
+ */
+
+@Data
+@NoArgsConstructor
+@ToString
+public class TaskEventMessage implements Serializable {
+ private String id;
+ private String eventName;
+ private String tenantId;
+}
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/socket/message/TaskMessage.java b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/socket/message/TaskMessage.java
new file mode 100644
index 00000000..02b9be2a
--- /dev/null
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/commons/io/socket/message/TaskMessage.java
@@ -0,0 +1,37 @@
+package org.camunda.bpm.extension.commons.io.socket.message;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * Task Message.
+ * Class for holding Task data.
+ */
+@Data
+@NoArgsConstructor
+@ToString
+public class TaskMessage implements Serializable {
+
+ private String assignee;
+ private Date createTime;
+ private String deleteReason;
+ private String description;
+ private Date dueDate;
+ private String eventName;
+ private String executionId;
+ private Date followUpDate;
+ private String id;
+ private String name;
+ private String owner;
+ private int priority;
+ private String processDefinitionId;
+ private String processInstanceId;
+ private String taskDefinitionKey;
+ private Map variables;
+ private String tenantId;
+}
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/listeners/BPMFormDataPipelineListener.java b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/listeners/BPMFormDataPipelineListener.java
index 05b0ae87..07f34a18 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/listeners/BPMFormDataPipelineListener.java
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/listeners/BPMFormDataPipelineListener.java
@@ -1,6 +1,5 @@
package org.camunda.bpm.extension.hooks.listeners;
-
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
@@ -10,46 +9,47 @@
import org.camunda.bpm.engine.delegate.TaskListener;
import org.camunda.bpm.engine.delegate.DelegateTask;
import org.camunda.bpm.extension.commons.connector.HTTPServiceInvoker;
-
import org.camunda.bpm.extension.hooks.exceptions.FormioServiceException;
import org.camunda.bpm.extension.hooks.listeners.data.FormElement;
+import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
-
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
-
+import javax.annotation.Resource;
import javax.inject.Named;
-
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
-
-import java.util.logging.Level;
-import java.util.logging.Logger;
+import java.util.Map;
+import java.util.Properties;
+import java.util.HashMap;
+import static org.camunda.bpm.extension.commons.utils.VariableConstants.FORM_URL;
/**
- * This class transforms all the form document data into CAM variables
- *
- * @author sumathi.thirumani@aot-technologies.com
+ * BPM Form Data Pipeline Listener.
+ * This class copies all the CAM variables into form document data.
*/
@Named("BPMFormDataPipelineListener")
public class BPMFormDataPipelineListener extends BaseListener implements TaskListener, ExecutionListener {
-
- private final Logger LOGGER = Logger.getLogger(BPMFormDataPipelineListener.class.getName());
-
+ // private final Logger LOGGER =
+ // Logger.getLogger(BPMFormDataPipelineListener.class.getName());
+ private final Logger LOGGER = LoggerFactory.getLogger(BPMFormDataPipelineListener.class);
private Expression fields;
-
+ @Resource(name = "bpmObjectMapper")
+ private ObjectMapper bpmObjectMapper;
@Autowired
private HTTPServiceInvoker httpServiceInvoker;
+ @Autowired
+ private Properties integrationCredentialProperties;
@Override
public void notify(DelegateExecution execution) {
try {
patchFormAttributes(execution);
} catch (IOException e) {
- handleException(execution,ExceptionSource.EXECUTION, e);
+ handleException(execution, ExceptionSource.EXECUTION, e);
}
}
@@ -63,38 +63,58 @@ public void notify(DelegateTask delegateTask) {
}
private void patchFormAttributes(DelegateExecution execution) throws IOException {
- String formUrl= MapUtils.getString(execution.getVariables(),"formUrl", null);
- if(StringUtils.isBlank(formUrl)) {
- LOGGER.log(Level.SEVERE,"Unable to read submission for "+execution.getVariables().get("formUrl"));
- return;
- }
- ResponseEntity response = httpServiceInvoker.execute(getUrl(execution), HttpMethod.PATCH, getModifiedFormElements(execution));
- if(response.getStatusCodeValue() != HttpStatus.OK.value()) {
- throw new FormioServiceException("Unable to get patch values for: "+ formUrl+ ". Message Body: " +
- response.getBody());
+ String formUrl = MapUtils.getString(execution.getVariables(), FORM_URL, null);
+ ResponseEntity response = null;
+ Boolean enableCustomSubmission = Boolean
+ .valueOf(integrationCredentialProperties.getProperty("forms.enableCustomSubmission"));
+ if (StringUtils.isBlank(formUrl)) {
+ LOGGER.error("Unable to read submission for Empty Url string");
+ } else {
+ if (enableCustomSubmission) {
+ // Form submission data to custom data store using custom url.
+ response = httpServiceInvoker.execute(getUrl(execution), HttpMethod.PATCH,
+ getModifiedFormElementsCustomSubmission(execution));
+ } else {
+ response = httpServiceInvoker.execute(getUrl(execution), HttpMethod.PATCH,
+ getModifiedFormElements(execution));
+ }
+ if (response.getStatusCodeValue() != HttpStatus.OK.value()) {
+ throw new FormioServiceException("Unable to get patch values for: " + formUrl + ". Message Body: " +
+ response.getBody());
+ }
}
}
-
- private String getUrl(DelegateExecution execution){
- return String.valueOf(execution.getVariables().get("formUrl"));
+ private String getUrl(DelegateExecution execution) {
+ return String.valueOf(execution.getVariables().get(FORM_URL));
}
private List getModifiedFormElements(DelegateExecution execution) throws IOException {
List elements = new ArrayList<>();
- ObjectMapper objectMapper = new ObjectMapper();
- List injectableFields = this.fields != null && this.fields.getValue(execution) != null ?
- objectMapper.readValue(String.valueOf(this.fields.getValue(execution)),List.class): null;
+ List injectableFields = this.fields != null && this.fields.getValue(execution) != null
+ ? bpmObjectMapper.readValue(String.valueOf(this.fields.getValue(execution)), List.class)
+ : null;
LOGGER.info("Invoking BPMFormDataPipelineListener for applicationId::" +
execution.getVariables().get("applicationId")
+ " process_pid::" +
execution.getVariables().get("process_pid"));
- for(String entry: injectableFields) {
- elements.add(new FormElement(entry,String.valueOf(execution.getVariable(entry))));
+ for (String entry : injectableFields) {
+ elements.add(new FormElement(entry, String.valueOf(execution.getVariable(entry))));
}
-
return elements;
}
-
-}
+ private Map> getModifiedFormElementsCustomSubmission(DelegateExecution execution)
+ throws IOException {
+ Map paramMap = new HashMap<>();
+ Map> dataMap = new HashMap<>();
+ List injectableFields = this.fields != null && this.fields.getValue(execution) != null
+ ? bpmObjectMapper.readValue(String.valueOf(this.fields.getValue(execution)), List.class)
+ : null;
+ for (String entry : injectableFields) {
+ paramMap.put(entry, String.valueOf(execution.getVariable(entry)));
+ }
+ dataMap.put("data", paramMap);
+ return dataMap;
+ }
+}
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/listeners/execution/ExternalSubmissionListener.java b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/listeners/execution/ExternalSubmissionListener.java
index 3de3e36f..4d624be7 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/listeners/execution/ExternalSubmissionListener.java
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/listeners/execution/ExternalSubmissionListener.java
@@ -18,15 +18,20 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
+import javax.annotation.Resource;
import javax.inject.Named;
-
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
+import static org.camunda.bpm.extension.commons.utils.VariableConstants.FORM_URL;
+import static org.camunda.bpm.extension.commons.utils.VariableConstants.APPLICATION_ID;
+
/**
- * This listener supports creation of form.io submission for instances created from external system
+ * This class supports creation of submission for instances created from
+ * external system
+ *
* @author sumathi.thirumani@aot-technologies.com
*/
@Named("ExternalSubmissionListener")
@@ -36,69 +41,70 @@ public class ExternalSubmissionListener extends BaseListener implements Executio
@Autowired
private FormSubmissionService formSubmissionService;
-
+ @Resource(name = "bpmObjectMapper")
+ private ObjectMapper bpmObjectMapper;
@Autowired
private HTTPServiceInvoker httpServiceInvoker;
private Expression formName;
- /**
- * Communicates with the form.io system to create a submission
- * Also, if an applicationId is not available, an applicationId will be created
- * and the same will be communicated to the form.io submission.
- *
- * @param execution The current execution instance
- */
@Override
public void notify(DelegateExecution execution) {
try {
String formUrl = getFormUrl(execution);
- String submissionId = formSubmissionService.createSubmission(formUrl, formSubmissionService.createFormSubmissionData(execution.getVariables()));
+ String submissionId = formSubmissionService.createSubmission(formUrl,
+ formSubmissionService.createFormSubmissionData(execution.getVariables()));
LOGGER.info("Creating submission::" + submissionId);
- if(StringUtils.isNotBlank(submissionId)){
- execution.setVariable("formUrl", formUrl+"/"+submissionId);
- if(execution.getVariable("applicationId") == null) {
+ if (StringUtils.isNotBlank(submissionId)) {
+ execution.setVariable(FORM_URL, formUrl + "/" + submissionId);
+ if (execution.getVariable("applicationId") == null) {
createApplication(execution, true);
-
+
// To update submissionId with applicationId
- formSubmissionService.updateSubmission(formUrl+"/"+submissionId, formSubmissionService.createFormSubmissionData(execution.getVariables()));
+ formSubmissionService.updateSubmission(formUrl + "/" + submissionId,
+ formSubmissionService.createFormSubmissionData(execution.getVariables()));
}
}
- } catch(IOException | RuntimeException ex) {
+ } catch (IOException | RuntimeException ex) {
handleException(execution, ExceptionSource.EXECUTION, ex);
}
}
private String getFormId(DelegateExecution execution) throws IOException {
- String formName = String.valueOf(this.formName.getValue(execution));
- return formSubmissionService.getFormIdByName(httpServiceInvoker.getProperties().getProperty("formio.url")+"/"+formName);
+ String formName = String.valueOf(this.formName.getValue(execution));
+ return formSubmissionService
+ .getFormIdByName(httpServiceInvoker.getProperties().getProperty("formio.url") + "/" + formName);
}
private String getFormUrl(DelegateExecution execution) throws IOException {
- return httpServiceInvoker.getProperties().getProperty("formio.url")+"/form/"+getFormId(execution)+"/submission";
+ return httpServiceInvoker.getProperties().getProperty("formio.url") + "/form/" + getFormId(execution)
+ + "/submission";
}
/**
*
* @param execution - DelegateExecution data
- * @param retryOnce - If formsflow api failed to respond 201 then the application will try once again and then it fail.
+ * @param retryOnce - If formsflow api failed to respond 201 then the
+ * application will try once again and then it fail.
* @throws JsonProcessingException
*/
private void createApplication(DelegateExecution execution, boolean retryOnce) throws JsonProcessingException {
- Map data = new HashMap<>();
- String formUrl = String.valueOf(execution.getVariable("formUrl"));
- data.put("formUrl",formUrl);
- data.put("formId",StringUtils.substringBetween(formUrl, "/form/", "/submission/"));
- data.put("submissionId",StringUtils.substringAfter(formUrl, "/submission/"));
- data.put("processInstanceId",execution.getProcessInstanceId());
- ResponseEntity response = httpServiceInvoker.execute(httpServiceInvoker.getProperties().getProperty("api.url")+"/application/create", HttpMethod.POST, getObjectMapper().writeValueAsString(data));
- if(response.getStatusCode().value() == HttpStatus.CREATED.value()) {
- JsonNode jsonNode = getObjectMapper().readTree(response.getBody());
+ Map data = new HashMap<>();
+ String formUrl = String.valueOf(execution.getVariable(FORM_URL));
+ data.put(FORM_URL, formUrl);
+ data.put("formId", StringUtils.substringBetween(formUrl, "/form/", "/submission/"));
+ data.put("submissionId", StringUtils.substringAfter(formUrl, "/submission/"));
+ data.put("processInstanceId", execution.getProcessInstanceId());
+ ResponseEntity response = httpServiceInvoker.execute(
+ httpServiceInvoker.getProperties().getProperty("api.url") + "/application/create", HttpMethod.POST,
+ bpmObjectMapper.writeValueAsString(data));
+ if (response.getStatusCode().value() == HttpStatus.CREATED.value()) {
+ JsonNode jsonNode = bpmObjectMapper.readTree(response.getBody());
String applicationId = jsonNode.get("id").asText();
- execution.setVariable("applicationId", applicationId);
+ execution.setVariable(APPLICATION_ID, applicationId);
} else {
- if(retryOnce) {
+ if (retryOnce) {
LOGGER.warn("Retrying the application create once more due to previous failure");
createApplication(execution, false);
} else {
@@ -107,9 +113,4 @@ private void createApplication(DelegateExecution execution, boolean retryOnce) t
}
}
}
-
- private ObjectMapper getObjectMapper(){
- return new ObjectMapper();
- }
-
}
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/listeners/task/AccessGrantNotifyListener.java b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/listeners/task/AccessGrantNotifyListener.java
index 0fcd09fd..0446a88b 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/listeners/task/AccessGrantNotifyListener.java
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/listeners/task/AccessGrantNotifyListener.java
@@ -19,9 +19,10 @@
import java.util.logging.Logger;
/**
+ * Access Grant Notify Listener.
* This component is aimed at sending notification to Access Groups
*
- * @author sumathi.thirumani@aot-technologies.com
+ * @author sumathi.thirumani@aot-technologies.com
*/
@Component
public class AccessGrantNotifyListener implements TaskListener, IMessageEvent {
@@ -29,7 +30,6 @@ public class AccessGrantNotifyListener implements TaskListener, IMessageEvent {
private Expression excludeGroup;
private Expression messageId;
-
private static final Logger LOGGER = Logger.getLogger(AccessGrantNotifyListener.class.getName());
private Expression category;
@@ -42,15 +42,17 @@ public class AccessGrantNotifyListener implements TaskListener, IMessageEvent {
public void notify(DelegateTask delegateTask) {
LOGGER.info("\n\nAccessGrantNotify listener invoked! " + delegateTask.getId());
List notifyGroup = new ArrayList<>();
- String excludeGroupValue = this.excludeGroup != null && this.excludeGroup.getValue(delegateTask.getExecution()) != null ?
- String.valueOf(this.excludeGroup.getValue(delegateTask.getExecution())) : null;
+ String excludeGroupValue = this.excludeGroup != null
+ && this.excludeGroup.getValue(delegateTask.getExecution()) != null
+ ? String.valueOf(this.excludeGroup.getValue(delegateTask.getExecution()))
+ : null;
List exclusionGroupList = new ArrayList<>();
LOGGER.info("Excluded group::" + excludeGroupValue);
- if(StringUtils.isNotBlank(excludeGroupValue)) {
- exclusionGroupList.add(excludeGroupValue.trim());
+ if (StringUtils.isNotBlank(excludeGroupValue)) {
+ exclusionGroupList.add(excludeGroupValue.strip());
}
List accessGroupList = getModifiedGroupsForTask(delegateTask, exclusionGroupList);
- String accessGroupListString = String.join("|",accessGroupList);
+ String accessGroupListString = String.join("|", accessGroupList);
for (String entry : accessGroupList) {
List emailsForGroup = getEmailsForGroup(delegateTask.getExecution(), entry);
notifyGroup.addAll(emailsForGroup);
@@ -58,7 +60,8 @@ public void notify(DelegateTask delegateTask) {
if (isNotify(delegateTask) && StringUtils.isBlank(delegateTask.getAssignee())) {
if (CollectionUtils.isNotEmpty(notifyGroup)) {
LOGGER.info("Sending an email to ::" + accessGroupListString);
- sendEmailNotification(delegateTask.getExecution(), notifyGroup, delegateTask.getId(), getCategory(delegateTask.getExecution()));
+ sendEmailNotification(delegateTask.getExecution(), notifyGroup, delegateTask.getId(),
+ getCategory(delegateTask.getExecution()));
delegateTask.getExecution().removeVariable("isNotify");
}
}
@@ -66,6 +69,7 @@ public void notify(DelegateTask delegateTask) {
/**
* Check if the current update event is a result of Notify action
+ *
* @param delegateTask The current task in context
* @return true - if the update event is a result of Notify; false - else
*/
@@ -76,23 +80,25 @@ private boolean isNotify(DelegateTask delegateTask) {
/**
* Sends an email.
+ *
* @param execution The current execution instance.
- * @param toEmails The recipients.
- * @param taskId The task id.
- * @param category The email category for the DMN.
+ * @param toEmails The recipients.
+ * @param taskId The task id.
+ * @param category The email category for the DMN.
*/
- private void sendEmailNotification(DelegateExecution execution, List toEmails, String taskId, String category) {
+ private void sendEmailNotification(DelegateExecution execution, List toEmails, String taskId,
+ String category) {
Set emails = new HashSet<>(toEmails);
- String toAddress = CollectionUtils.isNotEmpty(toEmails) ? StringUtils.join(emails,",") : null;
- if(StringUtils.isNotEmpty(toAddress)) {
+ String toAddress = CollectionUtils.isNotEmpty(toEmails) ? StringUtils.join(emails, ",") : null;
+ if (StringUtils.isNotEmpty(toAddress)) {
Map emailAttributes = new HashMap<>();
emailAttributes.put("to", toAddress);
emailAttributes.put("category", category);
- emailAttributes.put("name",getDefaultAddresseName());
- emailAttributes.put("taskid",taskId);
+ emailAttributes.put("name", getDefaultAddresseName());
+ emailAttributes.put("taskid", taskId);
log.info("Inside notify attributes:" + emailAttributes);
- if(StringUtils.isNotBlank(toAddress) && StringUtils.indexOf(toAddress,"@") > 0) {
- sendMessage(execution, emailAttributes,getMessageId(execution));
+ if (StringUtils.isNotBlank(toAddress) && StringUtils.indexOf(toAddress, "@") > 0) {
+ sendMessage(execution, emailAttributes, getMessageId(execution));
}
}
}
@@ -101,12 +107,12 @@ private void sendEmailNotification(DelegateExecution execution, List toE
* @param execution The current execution instance
* @return Returns the message category
*/
- private String getCategory(DelegateExecution execution){
+ private String getCategory(DelegateExecution execution) {
return String.valueOf(this.category.getValue(execution));
}
/**
- * @param delegateTask The task instance to send an email for.
+ * @param delegateTask The task instance to send an email for.
* @param exclusionGroup The groups to be excluded from the emails.
* @return The list of groups after removing the excluded groups.
*/
@@ -115,9 +121,9 @@ private List getModifiedGroupsForTask(DelegateTask delegateTask, List newGroupsAdded = new ArrayList<>();
if (CollectionUtils.isNotEmpty(identityLinks)) {
for (IdentityLink entry : identityLinks) {
- String grpId = entry.getGroupId().trim();
+ String grpId = entry.getGroupId().strip();
if (!exclusionGroup.contains(grpId)) {
- newGroupsAdded.add(entry.getGroupId().trim());
+ newGroupsAdded.add(entry.getGroupId().strip());
}
}
}
@@ -125,15 +131,17 @@ private List getModifiedGroupsForTask(DelegateTask delegateTask, List superVariables = new HashMap<>();
- List supFields = this.fields != null && this.fields.getValue(delegateTask) != null ?
- objectMapper.readValue(String.valueOf(this.fields.getValue(delegateTask)),List.class): null;
- for(String entry : supFields) {
+ Map superVariables = new HashMap<>();
+ List supFields = this.fields != null && this.fields.getValue(delegateTask) != null
+ ? bpmObjectMapper.readValue(String.valueOf(this.fields.getValue(delegateTask)), List.class)
+ : null;
+
+ for (String entry : supFields) {
superVariables.put(entry, delegateTask.getExecution().getVariables().get(entry));
}
LOGGER.info("Invoking FormConnectorListener for applicationId::" +
delegateTask.getExecution().getVariables().get("applicationId")
+ " process_pid::" +
delegateTask.getExecution().getVariables().get("process_pid"));
- return formSubmissionService.createSubmission(targetFormUrl, createFormSubmissionData(submission, superVariables, getPropogateData(delegateTask)));
+
+ return formSubmissionService.createSubmission(targetFormUrl,
+ createFormSubmissionData(submission, superVariables, getPropogateData(delegateTask)));
}
/**
- *
+ *
* @param submission
* @param superVariables
* @param propogateData
* @return
*/
- private String createFormSubmissionData(String submission, Map superVariables, String propogateData) {
+ private String createFormSubmissionData(String submission, Map superVariables,
+ String propogateData) {
try {
- JsonNode submissionNode = getObjectMapper().readTree(submission);
- JsonNode dataNode =submissionNode.get("data");
- if("Y".equals(propogateData)) {
- for(Map.Entry entry : superVariables.entrySet()) {
- ((ObjectNode)dataNode).put(entry.getKey(), getObjectMapper().convertValue(entry.getValue(), JsonNode.class));
+ JsonNode submissionNode = bpmObjectMapper.readTree(submission);
+ JsonNode dataNode = submissionNode.get("data");
+ if ("Y".equals(propogateData)) {
+ for (Map.Entry entry : superVariables.entrySet()) {
+ ((ObjectNode) dataNode).put(entry.getKey(),
+ bpmObjectMapper.convertValue(entry.getValue(), JsonNode.class));
}
- return getObjectMapper().writeValueAsString(new FormSubmission(dataNode));
+ return bpmObjectMapper.writeValueAsString(new FormSubmission(dataNode));
} else {
- return getObjectMapper().writeValueAsString(new FormSubmission(getObjectMapper().convertValue(superVariables, JsonNode.class)));
+ return bpmObjectMapper.writeValueAsString(
+ new FormSubmission(bpmObjectMapper.convertValue(superVariables, JsonNode.class)));
}
-
} catch (JsonProcessingException e) {
e.printStackTrace();
}
- return null;
+ return null;
}
/**
* Get the formID for associated name.
- *
+ *
* @param delegateTask
* @return
*/
@@ -119,25 +129,28 @@ private String getFormId(DelegateTask delegateTask) throws IOException {
.getExtensionElements()
.getElementsQuery()
.filterByType(CamundaProperties.class).singleResult();
-
List userTaskExtensionProperties = camundaProperties.getCamundaProperties()
.stream()
- .filter(camundaProperty ->
- camundaProperty.getCamundaName()
- .equals(getFormIdProperty()))
+ .filter(camundaProperty -> camundaProperty.getCamundaName()
+ .equals(getFormIdProperty()))
.collect(Collectors.toList());
+ if (CollectionUtils.isNotEmpty(userTaskExtensionProperties)) {
- if(CollectionUtils.isNotEmpty(userTaskExtensionProperties)) {
String formName = userTaskExtensionProperties.get(0).getCamundaValue();
- return formSubmissionService.getFormIdByName(StringUtils.substringBefore(getFormUrl(delegateTask),"/form/")+"/"+formName);
+ if (StringUtils.startsWith(formName, "$")) {
+ formName = String.valueOf(
+ delegateTask.getExecution().getVariable(StringUtils.substringBetween(formName, "${", "}")));
+ }
+ return formSubmissionService
+ .getFormIdByName(StringUtils.substringBefore(getFormUrl(delegateTask), "/form/") + "/" + formName);
}
-
return null;
}
/**
* Defines the form ID property.
+ *
* @return
*/
private String getFormIdProperty() {
@@ -146,40 +159,33 @@ private String getFormIdProperty() {
/**
* Returns the data propagation property value.
- *
+ *
* @param delegateTask
* @return
*/
- private String getPropogateData(DelegateTask delegateTask){
- if(this.copyDataIndicator != null &&
+ private String getPropogateData(DelegateTask delegateTask) {
+ if (this.copyDataIndicator != null &&
StringUtils.isNotBlank(String.valueOf(this.copyDataIndicator.getValue(delegateTask)))) {
return String.valueOf(this.copyDataIndicator.getValue(delegateTask));
}
return "N";
}
- /**
- * Returns Object Mapper Instance
- * @return
- */
- private ObjectMapper getObjectMapper(){
- return new ObjectMapper();
- }
-
/**
* Returns new URL for submission.
- *
+ *
* @param delegateTask
* @return
*/
private String getNewFormSubmissionUrl(DelegateTask delegateTask) throws IOException {
String formUrl = getFormUrl(delegateTask);
- return StringUtils.replace(formUrl, StringUtils.substringBetween(formUrl, "form/", "/submission"), getFormId(delegateTask));
+ return StringUtils.replace(formUrl, StringUtils.substringBetween(formUrl, "form/", "/submission"),
+ getFormId(delegateTask));
}
/**
* Returns the formURl from execution context
- *
+ *
* @param delegateTask
* @return
*/
@@ -189,14 +195,13 @@ private String getFormUrl(DelegateTask delegateTask) {
/**
* Returns the updated formUrl with new submission ID.
- *
+ *
* @param delegateTask
* @param submissionId
* @return
*/
private String getModifiedFormUrl(DelegateTask delegateTask, String submissionId) throws IOException {
- String formUrl = StringUtils.substringBefore(getFormUrl(delegateTask),"/form/");
- return formUrl+ "/form/" + getFormId(delegateTask) + "/submission/" + submissionId;
+ String formUrl = StringUtils.substringBefore(getFormUrl(delegateTask), "/form/");
+ return formUrl + "/form/" + getFormId(delegateTask) + "/submission/" + submissionId;
}
-
}
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/services/FormSubmissionService.java b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/services/FormSubmissionService.java
index 658702ee..06831cdc 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/services/FormSubmissionService.java
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/hooks/services/FormSubmissionService.java
@@ -1,6 +1,5 @@
package org.camunda.bpm.extension.hooks.services;
-
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -9,7 +8,7 @@
import org.camunda.bpm.engine.variable.Variables;
import org.camunda.bpm.engine.variable.value.FileValue;
import org.camunda.bpm.extension.commons.connector.HTTPServiceInvoker;
-import org.camunda.bpm.extension.commons.connector.support.FormTokenAccessHandler;
+import org.camunda.bpm.extension.commons.connector.FormioTokenServiceProvider;
import org.camunda.bpm.extension.hooks.exceptions.FormioServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -18,7 +17,7 @@
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
-
+import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
@@ -27,115 +26,120 @@
import java.util.logging.Logger;
import java.util.stream.Collectors;
-
@Qualifier("formSubmissionService")
@Service
public class FormSubmissionService {
private final Logger LOGGER = Logger.getLogger(FormSubmissionService.class.getName());
+ @Resource(name = "bpmObjectMapper")
+ private ObjectMapper bpmObjectMapper;
@Autowired
- private FormTokenAccessHandler formTokenAccessHandler;
+ private FormioTokenServiceProvider formioTokenServiceProvider;
@Autowired
private HTTPServiceInvoker httpServiceInvoker;
public String readSubmission(String formUrl) {
- ResponseEntity response = httpServiceInvoker.execute(formUrl, HttpMethod.GET, null);
- if(response.getStatusCode().value() == HttpStatus.OK.value()) {
+ ResponseEntity response = httpServiceInvoker.execute(formUrl, HttpMethod.GET, null);
+ if (response.getStatusCode().value() == HttpStatus.OK.value()) {
return response.getBody();
} else {
- throw new FormioServiceException("Unable to read submission for: "+ formUrl+ ". Message Body: " +
+ throw new FormioServiceException("Unable to read submission for: " + formUrl + ". Message Body: " +
response.getBody());
}
}
public String createRevision(String formUrl) throws IOException {
- String submission = readSubmission(formUrl);
- if(StringUtils.isBlank(submission)) {
- LOGGER.log(Level.SEVERE,"Unable to read submission for "+formUrl);
+ String submission = readSubmission(formUrl);
+ if (StringUtils.isBlank(submission)) {
+ LOGGER.log(Level.SEVERE, "Unable to read submission for " + formUrl);
return null;
}
- ObjectMapper objectMapper = new ObjectMapper();
- ResponseEntity response = httpServiceInvoker.execute(getSubmissionUrl(formUrl), HttpMethod.POST, submission);
- if(response.getStatusCode().value() == HttpStatus.CREATED.value()) {
- JsonNode jsonNode = objectMapper.readTree(response.getBody());
+
+ ResponseEntity response = httpServiceInvoker.execute(getSubmissionUrl(formUrl), HttpMethod.POST,
+ submission);
+ if (response.getStatusCode().value() == HttpStatus.CREATED.value()) {
+ JsonNode jsonNode = bpmObjectMapper.readTree(response.getBody());
String submissionId = jsonNode.get("_id").asText();
return submissionId;
} else {
- throw new FormioServiceException("Unable to create revision for: "+ formUrl+ ". Message Body: " +
+ throw new FormioServiceException("Unable to create revision for: " + formUrl + ". Message Body: " +
response.getBody());
}
}
public String createSubmission(String formUrl, String submission) throws IOException {
- ObjectMapper objectMapper = new ObjectMapper();
- ResponseEntity response = httpServiceInvoker.execute(getSubmissionUrl(formUrl), HttpMethod.POST, submission);
- if(response.getStatusCode().value() == HttpStatus.CREATED.value()) {
- JsonNode jsonNode = objectMapper.readTree(response.getBody());
+
+ ResponseEntity response = httpServiceInvoker.execute(getSubmissionUrl(formUrl), HttpMethod.POST,
+ submission);
+ if (response.getStatusCode().value() == HttpStatus.CREATED.value()) {
+ JsonNode jsonNode = bpmObjectMapper.readTree(response.getBody());
String submissionId = jsonNode.get("_id").asText();
return submissionId;
} else {
- throw new FormioServiceException("Unable to create submission for: "+ formUrl+ ". Message Body: " +
+ throw new FormioServiceException("Unable to create submission for: " + formUrl + ". Message Body: " +
response.getBody());
}
}
public void updateSubmission(String submissionUrl, String submission) throws IOException {
- ObjectMapper objectMapper = new ObjectMapper();
- ResponseEntity response = httpServiceInvoker.execute(submissionUrl, HttpMethod.PUT, submission);
- if(response.getStatusCode().value() != HttpStatus.OK.value()) {
- LOGGER.log(Level.SEVERE,"Unable to update submission for "+submissionUrl +
+
+ ResponseEntity response = httpServiceInvoker.execute(submissionUrl, HttpMethod.PUT, submission);
+ if (response.getStatusCode().value() != HttpStatus.OK.value()) {
+ LOGGER.log(Level.SEVERE, "Unable to update submission for " + submissionUrl +
" Response code::" + response.getStatusCode().value());
- throw new FormioServiceException("Unable to update submission for: "+ submissionUrl + ". Message Body: " +
+ throw new FormioServiceException("Unable to update submission for: " + submissionUrl + ". Message Body: " +
response.getBody());
}
}
public String getFormIdByName(String formUrl) throws IOException {
- ObjectMapper objectMapper = new ObjectMapper();
- ResponseEntity response = httpServiceInvoker.execute(formUrl, HttpMethod.GET, null);
- if(response.getStatusCode().value() == HttpStatus.OK.value()) {
- JsonNode jsonNode = objectMapper.readTree(response.getBody());
+
+ ResponseEntity response = httpServiceInvoker.execute(formUrl, HttpMethod.GET, null);
+ if (response.getStatusCode().value() == HttpStatus.OK.value()) {
+ JsonNode jsonNode = bpmObjectMapper.readTree(response.getBody());
String formId = jsonNode.get("_id").asText();
return formId;
} else {
- throw new FormioServiceException("Unable to get name for: "+ formUrl+ ". Message Body: " +
+ throw new FormioServiceException("Unable to get name for: " + formUrl + ". Message Body: " +
response.getBody());
}
}
- private String getSubmissionUrl(String formUrl){
- if(StringUtils.endsWith(formUrl,"submission")) {
+ private String getSubmissionUrl(String formUrl) {
+ if (StringUtils.endsWith(formUrl, "submission")) {
return formUrl;
}
- return StringUtils.substringBeforeLast(formUrl,"/");
+ return StringUtils.substringBeforeLast(formUrl, "/");
}
- public Map retrieveFormValues(String formUrl) throws IOException {
- Map fieldValues = new HashMap();
+ public Map retrieveFormValues(String formUrl) throws IOException {
+ Map fieldValues = new HashMap();
String submission = readSubmission(formUrl);
- if(StringUtils.isNotEmpty(submission)) {
- JsonNode dataNode = getObjectMapper().readTree(submission);
+ if (StringUtils.isNotEmpty(submission)) {
+ JsonNode dataNode = bpmObjectMapper.readTree(submission);
Iterator> dataElements = dataNode.findPath("data").fields();
while (dataElements.hasNext()) {
Map.Entry entry = dataElements.next();
- if(StringUtils.endsWithIgnoreCase(entry.getKey(),"_file")) {
+ if (StringUtils.endsWithIgnoreCase(entry.getKey(), "_file")) {
List fileNames = new ArrayList();
- if(entry.getValue().isArray()) {
+ if (entry.getValue().isArray()) {
for (JsonNode fileNode : entry.getValue()) {
- byte[] bytes = Base64.getDecoder().decode(StringUtils.substringAfterLast(fileNode.get("url").asText(), "base64,"));
+ byte[] bytes = Base64.getDecoder()
+ .decode(StringUtils.substringAfterLast(fileNode.get("url").asText(), "base64,"));
FileValue fileValue = Variables.fileValue(fileNode.get("originalName").asText())
.file(bytes)
.mimeType(fileNode.get("type").asText())
.create();
fileNames.add(fileNode.get("originalName").asText());
- fieldValues.put(StringUtils.substringBeforeLast(fileNode.get("originalName").asText(),".")+entry.getKey(), fileValue);
- if(fileNames.size() > 0) {
- fieldValues.put(entry.getKey()+"_uploadname", StringUtils.join(fileNames, ","));
+ fieldValues.put(StringUtils.substringBeforeLast(fileNode.get("originalName").asText(), ".")
+ + entry.getKey(), fileValue);
+ if (fileNames.size() > 0) {
+ fieldValues.put(entry.getKey() + "_uploadname", StringUtils.join(fileNames, ","));
}
}
}
- } else{
+ } else {
fieldValues.put(entry.getKey(), convertToOriginType(entry.getValue()));
}
}
@@ -145,55 +149,51 @@ public Map retrieveFormValues(String formUrl) throws IOException
private Object convertToOriginType(JsonNode value) throws IOException {
Object fieldValue;
- if(value.isNull()){
+ if (value.isNull()) {
fieldValue = null;
- } else if(value.isBoolean()){
+ } else if (value.isBoolean()) {
fieldValue = value.booleanValue();
- } else if(value.isInt()){
+ } else if (value.isInt()) {
fieldValue = value.intValue();
- } else if(value.isBinary()){
+ } else if (value.isBinary()) {
fieldValue = value.binaryValue();
- } else if(value.isLong()){
+ } else if (value.isLong()) {
fieldValue = value.asLong();
- } else if(value.isDouble()){
+ } else if (value.isDouble()) {
fieldValue = value.asDouble();
- } else if(value.isBigDecimal()){
+ } else if (value.isBigDecimal()) {
fieldValue = value.decimalValue();
- } else if(value.isTextual()){
+ } else if (value.isTextual()) {
fieldValue = value.asText();
- } else{
+ } else {
fieldValue = value.toString();
}
- if(Objects.equals(fieldValue, "")) {
+ if (Objects.equals(fieldValue, "")) {
fieldValue = null;
}
return fieldValue;
}
- public String createFormSubmissionData(Map bpmVariables) throws IOException {
+ public String createFormSubmissionData(Map bpmVariables) throws IOException {
List fileKeys = bpmVariables.keySet().stream()
.filter((key) -> key.endsWith("_file"))
.collect(Collectors.toList());
- for (String fileKey: fileKeys) {
+ for (String fileKey : fileKeys) {
InputStream file = (InputStream) bpmVariables.get(fileKey);
byte[] bytes = IOUtils.toByteArray(file);
String fileString = new String(bytes, StandardCharsets.UTF_8);
bpmVariables.put(fileKey, fileString);
}
- Map> data = new HashMap<>();
- data.put("data",bpmVariables);
- return getObjectMapper().writeValueAsString(data);
- }
-
- private ObjectMapper getObjectMapper(){
- return new ObjectMapper();
+ Map> data = new HashMap<>();
+ data.put("data", bpmVariables);
+ return bpmObjectMapper.writeValueAsString(data);
}
@Deprecated
public String getAccessToken() {
- return formTokenAccessHandler.getAccessToken();
+ return formioTokenServiceProvider.getAccessToken();
}
-}
\ No newline at end of file
+}
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/keycloak/plugin/KeycloakIdentityProviderSession.java b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/keycloak/plugin/KeycloakIdentityProviderSession.java
index 3f4ff681..e82cda01 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/keycloak/plugin/KeycloakIdentityProviderSession.java
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/keycloak/plugin/KeycloakIdentityProviderSession.java
@@ -4,6 +4,8 @@
import java.util.List;
import org.camunda.bpm.engine.identity.Group;
+import org.camunda.bpm.engine.identity.Tenant;
+import org.camunda.bpm.engine.identity.TenantQuery;
import org.camunda.bpm.engine.identity.User;
import org.camunda.bpm.engine.impl.interceptor.CommandContext;
import org.camunda.bpm.extension.keycloak.*;
@@ -19,13 +21,21 @@
public class KeycloakIdentityProviderSession
extends org.camunda.bpm.extension.keycloak.KeycloakIdentityProviderSession {
+ private CustomConfig config;
+ private TenantService tenantService;
+ protected QueryCache> tenantQueryCache;
+
public KeycloakIdentityProviderSession(KeycloakConfiguration keycloakConfiguration, KeycloakRestTemplate restTemplate, KeycloakContextProvider keycloakContextProvider,
- QueryCache> userQueryCache, QueryCache> groupQueryCache,
+ QueryCache> userQueryCache,
+ QueryCache> groupQueryCache,
+ QueryCache> tenantQueryCache,
QueryCache checkPasswordCache,
- String webClientId, boolean enableClientAuth) {
+ CustomConfig config) {
super(keycloakConfiguration, restTemplate, keycloakContextProvider, userQueryCache, groupQueryCache, checkPasswordCache);
- this.groupService = new KeycloakGroupService(keycloakConfiguration, restTemplate, keycloakContextProvider, webClientId, enableClientAuth);
- this.userService = new KeycloakUserService(keycloakConfiguration, restTemplate, keycloakContextProvider, webClientId, enableClientAuth);
+ this.config = config;
+ this.groupService = new KeycloakGroupService(keycloakConfiguration, restTemplate, keycloakContextProvider, config);
+ this.userService = new KeycloakUserService(keycloakConfiguration, restTemplate, keycloakContextProvider, config);
+ this.tenantQueryCache = tenantQueryCache;
}
/**
@@ -75,4 +85,47 @@ private List doFindUserByQueryCriteria(CacheableKeycloakUserQuery userQuer
this.userService.requestUsersWithoutGroupId(userQuery);
}
-}
\ No newline at end of file
+ /**
+ * find groups meeting given group query criteria (with cache lookup and post
+ * processing).
+ *
+ * @param groupQuery the group query
+ * @return list of matching groups
+ */
+ protected List findGroupByQueryCriteria(KeycloakGroupQuery groupQuery) {
+ StringBuilder resultLogger = new StringBuilder();
+
+ if (KeycloakPluginLogger.INSTANCE.isDebugEnabled()) {
+ resultLogger.append("Keycloak group query results: [");
+ }
+
+ List allMatchingGroups = groupQueryCache.getOrCompute(CacheableKeycloakGroupQuery.of(groupQuery),
+ this::doFindGroupByQueryCriteria);
+
+ List processedGroups = groupService.postProcessResults(groupQuery, allMatchingGroups, resultLogger);
+
+ if (KeycloakPluginLogger.INSTANCE.isDebugEnabled()) {
+ resultLogger.append("]");
+ KeycloakPluginLogger.INSTANCE.groupQueryResult(resultLogger.toString());
+ }
+
+ return processedGroups;
+ }
+
+ /**
+ * find all groups meeting given group query criteria (without cache lookup or
+ * post processing).
+ *
+ * @param groupQuery the group query
+ * @return list of matching groups
+ */
+ private List doFindGroupByQueryCriteria(CacheableKeycloakGroupQuery groupQuery) {
+ if (StringUtils.hasLength(groupQuery.getUserId())) {
+ // if restriction on userId is provided, we're searching within the groups of a
+ // single user
+ return groupService.requestGroupsByUserId(groupQuery);
+ } else {
+ return groupService.requestGroupsWithoutUserId(groupQuery);
+ }
+ }
+}
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/keycloak/plugin/KeycloakUserService.java b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/keycloak/plugin/KeycloakUserService.java
index 1122703c..28808c12 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/keycloak/plugin/KeycloakUserService.java
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/main/java/org/camunda/bpm/extension/keycloak/plugin/KeycloakUserService.java
@@ -13,6 +13,11 @@
import org.springframework.web.client.RestClientException;
import org.springframework.util.StringUtils;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.oauth2.core.oidc.user.OidcUser;
+import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
+
import java.util.logging.Logger;
import org.springframework.http.ResponseEntity;
@@ -27,6 +32,7 @@
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
+
import static org.camunda.bpm.extension.keycloak.json.JsonUtil.*;
/**
@@ -40,12 +46,19 @@ public class KeycloakUserService extends org.camunda.bpm.extension.keycloak.Key
private String webClientId;
private boolean enableClientAuth;
+ private boolean enableMultiTenancy;
+ private TenantService tenantService;
public KeycloakUserService(KeycloakConfiguration keycloakConfiguration, KeycloakRestTemplate restTemplate,
- KeycloakContextProvider keycloakContextProvider,String webClientId,boolean enableClientAuth) {
+ KeycloakContextProvider keycloakContextProvider, CustomConfig config) {
super(keycloakConfiguration, restTemplate, keycloakContextProvider);
- this.webClientId = webClientId;
- this.enableClientAuth = enableClientAuth;
+
+ this.webClientId = config.getWebClientId();
+ this.enableClientAuth = config.isEnableClientAuth();
+ this.enableMultiTenancy = config.isEnableMultiTenancy();
+ if (this.enableMultiTenancy) {
+ this.tenantService = new TenantService(restTemplate, keycloakContextProvider, config);
+ }
}
@Override
@@ -120,4 +133,4 @@ private UserEntity transformUser(JsonObject result) throws JsonException {
user.setLastName(lastName);
return user;
}
-}
\ No newline at end of file
+}
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/main/resources/application.yaml b/apps/forms-flow-ai/forms-flow-bpm/src/main/resources/application.yaml
index e37f43a5..bd7efd7c 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/src/main/resources/application.yaml
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/main/resources/application.yaml
@@ -9,16 +9,18 @@ formbuilder.pipeline.service.username: ${CAMUNDA_FORMBUILDER_PIPELINE_USERNAME}
formbuilder.pipeline.service.password: ${CAMUNDA_FORMBUILDER_PIPELINE_PASSWORD}
formbuilder.pipeline.service.bpm-url: ${CAMUNDA_FORMBUILDER_PIPELINE_BPM_URL}
-spring.datasource:
- jdbc-url: ${CAMUNDA_JDBC_URL:jdbc:h2:./camunda-db;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE}
- username: ${CAMUNDA_JDBC_USER:sa}
- password: ${CAMUNDA_JDBC_PASSWORD:sa}
- driverClassName: ${CAMUNDA_JDBC_DRIVER:org.h2.Driver}
- type: com.zaxxer.hikari.HikariDataSource
- connectionTimeout: ${CAMUNDA_HIKARI_CONN_TIMEOUT:30000}
- idleTimeout: ${CAMUNDA_HIKARI_IDLE_TIMEOUT:600000}
- maximumPoolSize: ${CAMUNDA_HIKARI_MAX_POOLSIZE:10}
- validationTimeout: ${CAMUNDA_HIKARI_VALID_TIMEOUT:5000}
+spring:
+ datasource:
+ jdbc-url: ${CAMUNDA_JDBC_URL:jdbc:h2:./camunda-db;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE}
+ username: ${CAMUNDA_JDBC_USER:sa}
+ password: ${CAMUNDA_JDBC_PASSWORD:sa}
+ driverClassName: ${CAMUNDA_JDBC_DRIVER:org.h2.Driver}
+ type: com.zaxxer.hikari.HikariDataSource
+ minimum-idle: 10
+ connectionTimeout: ${CAMUNDA_HIKARI_CONN_TIMEOUT:30000}
+ idleTimeout: ${CAMUNDA_HIKARI_IDLE_TIMEOUT:600000}
+ maximumPoolSize: ${CAMUNDA_HIKARI_MAX_POOLSIZE:10}
+ validationTimeout: ${CAMUNDA_HIKARI_VALID_TIMEOUT:5000}
analytics.datasource:
jdbc-url: ${CAMUNDA_JDBC_URL}
@@ -33,8 +35,14 @@ analytics.datasource:
formsflow.ai:
+ forms:
+ enableCustomSubmission: ${CUSTOM_SUBMISSION_ENABLED:false}
+ custom_submission:
+ url: ${CUSTOM_SUBMISSION_URL}
api:
url: ${FORMSFLOW_API_URL}
+ analysis:
+ url: ${DATA_ANALYSIS_URL}
formio:
url: ${FORMIO_URL}
security:
@@ -69,9 +77,9 @@ info:
app:
name: "Camunda"
description: "formsflow.ai Engine"
- version: "7.15"
+ version: "7.17"
java:
- version: "11"
+ version: "17"
# Enable the below given block for session management of camunda. This is not required for externalised tasklist.
#session.datasource:
@@ -86,6 +94,8 @@ info:
# validationTimeout: ${CAMUNDA_SESSION_HIKARI_VALID_TIMEOUT:5000}
camunda.bpm:
+ job-execution:
+ enabled: true
history-level: ${CAMUNDA_BPM_HISTORY_LEVEL:none}
authorization:
enabled: ${CAMUNDA_AUTHORIZATION_FLAG:true}
@@ -95,7 +105,7 @@ camunda.bpm:
webapp:
application-path: /
csrf:
- enable-secure-cookie: true
+ enable-secure-cookie: ${SESSION_COOKIE_SECURE:true}
header-security:
content-security-policy-disabled: false
content-security-policy-value: base-uri 'self';
@@ -104,24 +114,27 @@ camunda.bpm:
form-action 'self';
frame-ancestors 'none';
object-src 'none'
- job-execution:
- core-pool-size: ${CAMUNDA_JOB_CORE_POOL_SIZE:3}
- lock-time-in-millis: ${CAMUNDA_JOB_LOCK_TIME_MILLIS:300000}
- max-jobs-per-acquisition: ${CAMUNDA_JOB_MAXJOBS_PER_ACQUISITION:3}
- max-pool-size: ${CAMUNDA_JOB_MAX_POOL_SIZE:10}
- queue-capacity: ${CAMUNDA_JOB_QUEUE_SIZE:3}
- wait-time-in-millis: ${CAMUNDA_JOB_WAIT_TIME_MILLIS:5000}
- max-wait: ${CAMUNDA_JOB_MAX_WAIT:60000}
- metrics:
- enabled: ${CAMUNDA_METRICS_FLAG:true}
+ # job-execution:
+ # core-pool-size: ${CAMUNDA_JOB_CORE_POOL_SIZE:3}
+ # lock-time-in-millis: ${CAMUNDA_JOB_LOCK_TIME_MILLIS:300000}
+ # max-jobs-per-acquisition: ${CAMUNDA_JOB_MAXJOBS_PER_ACQUISITION:3}
+ # max-pool-size: ${CAMUNDA_JOB_MAX_POOL_SIZE:10}
+ # queue-capacity: ${CAMUNDA_JOB_QUEUE_SIZE:3}
+ # wait-time-in-millis: ${CAMUNDA_JOB_WAIT_TIME_MILLIS:5000}
+ # max-wait: ${CAMUNDA_JOB_MAX_WAIT:60000}
+ # metrics:
+ # enabled: ${CAMUNDA_METRICS_FLAG:true}
server:
error:
include-message: always
port: 8080
- servlet.context-path: /camunda
+ servlet:
+ context-path: /camunda
session:
cookie:
- secure: true
+ secure: ${SESSION_COOKIE_SECURE:true}
+ max-age: 1800
+ http-only: true
# Camunda Rest API
@@ -203,7 +216,13 @@ websocket:
messageType: ${WEBSOCKET_MESSAGE_TYPE:TASK_EVENT}
messageEvents: ${WEBSOCKET_MESSAGE_EVENTS:DEFAULT}
messageBroker:
- host: ${WEBSOCKET_BROKER_HOST}
- port: ${WEBSOCKET_BROKER_PORT}
- passcode: ${WEBSOCKET_BROKER_PASSCODE}
+ host: ${REDIS_HOST}
+ port: ${REDIS_PORT}
+ passcode: ${REDIS_PASSCODE}
+ enableRedis: ${REDIS_ENABLED:false}
+
+# disable redis
+spring.data.redis.repositories.enabled: false
+spring.autoconfigure.exclude:
+ - org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/test/java/org/camunda/bpm/extension/commons/connector/support/ApplicationAccessHandlerTest.java b/apps/forms-flow-ai/forms-flow-bpm/src/test/java/org/camunda/bpm/extension/commons/connector/support/ApplicationAccessHandlerTest.java
index c20f7207..37dc3eca 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/src/test/java/org/camunda/bpm/extension/commons/connector/support/ApplicationAccessHandlerTest.java
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/test/java/org/camunda/bpm/extension/commons/connector/support/ApplicationAccessHandlerTest.java
@@ -2,11 +2,14 @@
import static org.junit.Assert.assertEquals;
+import org.camunda.bpm.extension.commons.ro.req.IRequest;
+import org.camunda.bpm.extension.commons.ro.res.IResponse;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
@@ -17,7 +20,7 @@
import java.util.function.Consumer;
-import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -28,47 +31,47 @@
@ExtendWith(SpringExtension.class)
class ApplicationAccessHandlerTest {
- @InjectMocks
- private ApplicationAccessHandler applicationAccessHandler;
+ @InjectMocks
+ private ApplicationAccessHandler applicationAccessHandler;
- @Mock
- private WebClient unAuthenticatedWebClient;
+ @Mock
+ private WebClient unAuthenticatedWebClient;
- @Mock
- private OAuth2RestTemplate oAuth2RestTemplate;
+ @Mock
+ private OAuth2RestTemplate oAuth2RestTemplate;
- /**
- * This test perform a positive test over ApplicationAccessHandler
- * This will validate the response entity is Success
- */
- @Test
- public void testExchangeSuccess() {
- final String apiUrl = "http://localhost:5000/api/application/123";
- WebClient.RequestBodyUriSpec requestBodyUriSpec = mock(WebClient.RequestBodyUriSpec.class);
- when(unAuthenticatedWebClient.method(any(HttpMethod.class)))
- .thenReturn(requestBodyUriSpec);
- when(requestBodyUriSpec.uri(anyString()))
- .thenReturn(requestBodyUriSpec);
- when(requestBodyUriSpec.accept(any(MediaType.class)))
- .thenReturn(requestBodyUriSpec);
- when(requestBodyUriSpec.header(anyString(), anyString()))
- .thenReturn(requestBodyUriSpec);
- OAuth2AccessToken oAuth2AccessToken = mock(OAuth2AccessToken.class);
- when(oAuth2RestTemplate.getAccessToken())
- .thenReturn(oAuth2AccessToken);
- when(requestBodyUriSpec.headers(any(Consumer.class)))
- .thenReturn(requestBodyUriSpec);
- WebClient.RequestHeadersSpec requestHeadersSpec = mock(WebClient.RequestHeadersSpec.class);
- when(requestBodyUriSpec.body(any(Mono.class), any(Class.class)))
- .thenReturn(requestHeadersSpec);
- WebClient.ResponseSpec responseSpec = mock(WebClient.ResponseSpec.class);
- when(requestHeadersSpec.retrieve()).thenReturn(responseSpec);
- Mono> response = Mono.just(ResponseEntity.ok("Success"));
- when(responseSpec.toEntity(String.class))
- .thenReturn(response);
+ /**
+ * This test perform a positive test over ApplicationAccessHandler
+ * This will validate the response entity is Success
+ */
+ @Test
+ public void testExchangeSuccess() {
+ final String apiUrl = "http://localhost:5000/api/application/123";
+ WebClient.RequestBodyUriSpec requestBodyUriSpec = mock(WebClient.RequestBodyUriSpec.class);
+ when(unAuthenticatedWebClient.method(any(HttpMethod.class)))
+ .thenReturn(requestBodyUriSpec);
+ when(requestBodyUriSpec.uri(anyString()))
+ .thenReturn(requestBodyUriSpec);
+ when(requestBodyUriSpec.accept(any(MediaType.class)))
+ .thenReturn(requestBodyUriSpec);
+ when(requestBodyUriSpec.header(anyString(), anyString()))
+ .thenReturn(requestBodyUriSpec);
+ OAuth2AccessToken oAuth2AccessToken = mock(OAuth2AccessToken.class);
+ when(oAuth2RestTemplate.getAccessToken())
+ .thenReturn(oAuth2AccessToken);
+ when(requestBodyUriSpec.headers(any(Consumer.class)))
+ .thenReturn(requestBodyUriSpec);
+ WebClient.RequestHeadersSpec requestHeadersSpec = mock(WebClient.RequestHeadersSpec.class);
+ when(requestBodyUriSpec.body(any(Mono.class), any(Class.class)))
+ .thenReturn(requestHeadersSpec);
+ WebClient.ResponseSpec responseSpec = mock(WebClient.ResponseSpec.class);
+ when(requestHeadersSpec.retrieve()).thenReturn(responseSpec);
+ Mono> response = Mono.just(ResponseEntity.ok("Success"));
+ when(responseSpec.toEntity(String.class))
+ .thenReturn(response);
- ResponseEntity data = applicationAccessHandler.exchange(apiUrl, HttpMethod.GET, "{}");
- assertEquals(data.getBody(), "Success");
- }
+ ResponseEntity data = applicationAccessHandler.exchange(apiUrl, HttpMethod.GET, "{}");
+ assertEquals(data.getBody(), "Success");
+ }
}
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-bpm/src/test/java/org/camunda/bpm/extension/commons/io/event/CamundaEventListenerTest.java b/apps/forms-flow-ai/forms-flow-bpm/src/test/java/org/camunda/bpm/extension/commons/io/event/CamundaEventListenerTest.java
index c650e825..0333ecb5 100644
--- a/apps/forms-flow-ai/forms-flow-bpm/src/test/java/org/camunda/bpm/extension/commons/io/event/CamundaEventListenerTest.java
+++ b/apps/forms-flow-ai/forms-flow-bpm/src/test/java/org/camunda/bpm/extension/commons/io/event/CamundaEventListenerTest.java
@@ -1,110 +1,128 @@
package org.camunda.bpm.extension.commons.io.event;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.camunda.bpm.engine.delegate.DelegateTask;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.data.redis.core.StringRedisTemplate;
+//import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.util.ReflectionTestUtils;
-
+import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
-
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;
+import static org.camunda.bpm.extension.commons.utils.VariableConstants.FORM_URL;
+import static org.camunda.bpm.extension.commons.utils.VariableConstants.APPLICATION_STATUS;
+import static org.camunda.bpm.extension.commons.utils.VariableConstants.APPLICATION_ID;
/**
+ * Camunda EventListener Test.
* Test class for CamundaEventListener
*/
@ExtendWith(SpringExtension.class)
public class CamundaEventListenerTest {
+ @InjectMocks
+ public CamundaEventListener camundaEventListener;
- @InjectMocks
- public CamundaEventListener camundaEventListener;
+ @Mock
+ private StringRedisTemplate template;
- @Mock
- private StringRedisTemplate template;
+ // @Mock
+ // private SimpMessagingTemplate template;
- /**
- * Test perform a positive test over onTaskEventListener
- * This test will validate the template
- */
- @Test
- public void onTaskEventListener_with_defaultEvents(){
- DelegateTask delegateTask = mock(DelegateTask.class);
- when(delegateTask.getEventName())
- .thenReturn("create");
+ @BeforeEach
+ public void setup() {
+ try {
+ Field field = camundaEventListener.getClass().getDeclaredField("bpmObjectMapper");
+ field.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ e.printStackTrace();
+ }
+ ObjectMapper objectMapper = new ObjectMapper();
+ ReflectionTestUtils.setField(this.camundaEventListener, "bpmObjectMapper", objectMapper);
+ }
- ReflectionTestUtils.setField(camundaEventListener, "messageCategory", "TASK_EVENT_DETAILS,TASK_EVENT");
- ReflectionTestUtils.setField(camundaEventListener, "messageEvents", "ALL");
- Map variables = new HashMap<>();
- variables.put("applicationId" , "id1");
- variables.put("formUrl" , "http://localhost:3001");
- variables.put("applicationStatus" , "New");
- when(delegateTask.getVariables())
- .thenReturn(variables);
- camundaEventListener.onTaskEventListener(delegateTask);
- ArgumentCaptor captor = ArgumentCaptor.forClass(String.class);
- verify(template, times(2)).convertAndSend(anyString(), captor.capture());
- assertEquals("{\"assignee\":null,\"createTime\":null,\"deleteReason\":null,\"description\":null,\"dueDate\":null,\"eventName\":\"create\",\"executionId\":null,\"followUpDate\":null,\"id\":null,\"name\":null,\"owner\":null,\"priority\":0,\"processDefinitionId\":null,\"processInstanceId\":null,\"taskDefinitionKey\":null,\"variables\":{\"applicationStatus\":null,\"formUrl\":null,\"applicationId\":null}}",
- captor.getAllValues().get(0));
- assertEquals("{\"id\":null,\"eventName\":\"create\"}", captor.getAllValues().get(1));
- }
+ /**
+ * Test perform a positive test over onTaskEventListener
+ * This test will validate the template
+ */
+ @Test
+ public void onTaskEventListener_with_defaultEvents() {
+ DelegateTask delegateTask = mock(DelegateTask.class);
+ when(delegateTask.getEventName())
+ .thenReturn("create");
+ ReflectionTestUtils.setField(camundaEventListener, "messageCategory", "TASK_EVENT_DETAILS,TASK_EVENT");
+ ReflectionTestUtils.setField(camundaEventListener, "messageEvents", "ALL");
+ Map variables = new HashMap<>();
+ variables.put(APPLICATION_ID, "id1");
+ variables.put(FORM_URL, "http://localhost:3001");
+ variables.put(APPLICATION_STATUS, "New");
+ when(delegateTask.getVariables())
+ .thenReturn(variables);
+ camundaEventListener.onTaskEventListener(delegateTask);
+ ArgumentCaptor captor = ArgumentCaptor.forClass(String.class);
+ verify(template, times(2)).convertAndSend(anyString(), captor.capture());
+ assertEquals("{\"assignee\":null,\"createTime\":null,\"deleteReason\":null,\"description\":null,\"dueDate\":null,\"eventName\":\"create\",\"executionId\":null,\"followUpDate\":null,\"id\":null,\"name\":null,\"owner\":null,\"priority\":0,\"processDefinitionId\":null,\"processInstanceId\":null,\"taskDefinitionKey\":null,\"variables\":{\"applicationStatus\":null,\"formUrl\":null,\"applicationId\":null},\"tenantId\":null}",
+ captor.getAllValues().get(0));
+ assertEquals("{\"id\":null,\"eventName\":\"create\",\"tenantId\":null}", captor.getAllValues().get(1));
+ }
- /**
- * Test perform a positive test with default message events
- * This test will validate the template
- */
- @Test
- public void onTaskEventListener_with_default_messageEvents(){
- DelegateTask delegateTask = mock(DelegateTask.class);
- when(delegateTask.getEventName())
- .thenReturn("create");
+ /**
+ * Test perform a positive test with default message events
+ * This test will validate the template
+ */
+ @Test
+ public void onTaskEventListener_with_default_messageEvents() {
+ DelegateTask delegateTask = mock(DelegateTask.class);
+ when(delegateTask.getEventName())
+ .thenReturn("create");
+ ReflectionTestUtils.setField(camundaEventListener, "messageCategory", "TASK_EVENT_DETAILS,TASK_EVENT");
+ ReflectionTestUtils.setField(camundaEventListener, "messageEvents", "DEFAULT");
+ Map variables = new HashMap<>();
+ variables.put(APPLICATION_ID, "id1");
+ variables.put(FORM_URL, "http://localhost:3001");
+ variables.put(APPLICATION_STATUS, "New");
+ when(delegateTask.getVariables())
+ .thenReturn(variables);
+ camundaEventListener.onTaskEventListener(delegateTask);
+ ArgumentCaptor captor = ArgumentCaptor.forClass(String.class);
+ verify(template, times(2)).convertAndSend(anyString(), captor.capture());
+ assertEquals("{\"assignee\":null,\"createTime\":null,\"deleteReason\":null,\"description\":null,\"dueDate\":null,\"eventName\":\"create\",\"executionId\":null,\"followUpDate\":null,\"id\":null,\"name\":null,\"owner\":null,\"priority\":0,\"processDefinitionId\":null,\"processInstanceId\":null,\"taskDefinitionKey\":null,\"variables\":{\"applicationStatus\":null,\"formUrl\":null,\"applicationId\":null},\"tenantId\":null}",
+ captor.getAllValues().get(0));
+ assertEquals("{\"id\":null,\"eventName\":\"create\",\"tenantId\":null}", captor.getAllValues().get(1));
+ }
- ReflectionTestUtils.setField(camundaEventListener, "messageCategory", "TASK_EVENT_DETAILS,TASK_EVENT");
- ReflectionTestUtils.setField(camundaEventListener, "messageEvents", "DEFAULT");
- Map variables = new HashMap<>();
- variables.put("applicationId" , "id1");
- variables.put("formUrl" , "http://localhost:3001");
- variables.put("applicationStatus" , "New");
- when(delegateTask.getVariables())
- .thenReturn(variables);
- camundaEventListener.onTaskEventListener(delegateTask);
- ArgumentCaptor captor = ArgumentCaptor.forClass(String.class);
- verify(template, times(2)).convertAndSend(anyString(), captor.capture());
- assertEquals("{\"assignee\":null,\"createTime\":null,\"deleteReason\":null,\"description\":null,\"dueDate\":null,\"eventName\":\"create\",\"executionId\":null,\"followUpDate\":null,\"id\":null,\"name\":null,\"owner\":null,\"priority\":0,\"processDefinitionId\":null,\"processInstanceId\":null,\"taskDefinitionKey\":null,\"variables\":{\"applicationStatus\":null,\"formUrl\":null,\"applicationId\":null}}",
- captor.getAllValues().get(0));
- assertEquals("{\"id\":null,\"eventName\":\"create\"}", captor.getAllValues().get(1));
- }
+ /**
+ * Test perform a positive test with custom message events
+ * This test will validate the template
+ */
+ @Test
+ public void onTaskEventListener_with_custom_messageEvents() {
+ DelegateTask delegateTask = mock(DelegateTask.class);
+ when(delegateTask.getEventName())
+ .thenReturn("create");
+ ReflectionTestUtils.setField(camundaEventListener, "messageCategory", "TASK_EVENT_DETAILS,TASK_EVENT");
+ ReflectionTestUtils.setField(camundaEventListener, "messageEvents", "create");
+ Map variables = new HashMap<>();
+ variables.put(APPLICATION_ID, "id1");
+ variables.put(FORM_URL, "http://localhost:3001");
+ variables.put(APPLICATION_STATUS, "New");
+ when(delegateTask.getVariables())
+ .thenReturn(variables);
+ camundaEventListener.onTaskEventListener(delegateTask);
+ ArgumentCaptor captor = ArgumentCaptor.forClass(String.class);
+ verify(template, times(2)).convertAndSend(anyString(), captor.capture());
+ assertEquals(
+ "{\"assignee\":null,\"createTime\":null,\"deleteReason\":null,\"description\":null,\"dueDate\":null,\"eventName\":\"create\",\"executionId\":null,\"followUpDate\":null,\"id\":null,\"name\":null,\"owner\":null,\"priority\":0,\"processDefinitionId\":null,\"processInstanceId\":null,\"taskDefinitionKey\":null,\"variables\":{\"applicationStatus\":null,\"formUrl\":null,\"applicationId\":null},\"tenantId\":null}",
+ captor.getAllValues().get(0));
+ assertEquals("{\"id\":null,\"eventName\":\"create\",\"tenantId\":null}", captor.getAllValues().get(1));
- /**
- * Test perform a positive test with custom message events
- * This test will validate the template
- */
- @Test
- public void onTaskEventListener_with_custom_messageEvents() {
- DelegateTask delegateTask = mock(DelegateTask.class);
- when(delegateTask.getEventName())
- .thenReturn("create");
+ }
- ReflectionTestUtils.setField(camundaEventListener, "messageCategory", "TASK_EVENT_DETAILS,TASK_EVENT");
- ReflectionTestUtils.setField(camundaEventListener, "messageEvents", "create");
- Map variables = new HashMap<>();
- variables.put("applicationId", "id1");
- variables.put("formUrl", "http://localhost:3001");
- variables.put("applicationStatus", "New");
- when(delegateTask.getVariables())
- .thenReturn(variables);
- camundaEventListener.onTaskEventListener(delegateTask);
- ArgumentCaptor captor = ArgumentCaptor.forClass(String.class);
- verify(template, times(2)).convertAndSend(anyString(), captor.capture());
- assertEquals(
- "{\"assignee\":null,\"createTime\":null,\"deleteReason\":null,\"description\":null,\"dueDate\":null,\"eventName\":\"create\",\"executionId\":null,\"followUpDate\":null,\"id\":null,\"name\":null,\"owner\":null,\"priority\":0,\"processDefinitionId\":null,\"processInstanceId\":null,\"taskDefinitionKey\":null,\"variables\":{\"applicationStatus\":null,\"formUrl\":null,\"applicationId\":null}}",
- captor.getAllValues().get(0));
- assertEquals("{\"id\":null,\"eventName\":\"create\"}", captor.getAllValues().get(1));
- }
-
}
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-web/src/apiManager/services/bpmTaskServices.js b/apps/forms-flow-ai/forms-flow-web/src/apiManager/services/bpmTaskServices.js
index db981638..94600ef4 100644
--- a/apps/forms-flow-ai/forms-flow-web/src/apiManager/services/bpmTaskServices.js
+++ b/apps/forms-flow-ai/forms-flow-web/src/apiManager/services/bpmTaskServices.js
@@ -1,3 +1,4 @@
+
/* istanbul ignore file */
import {httpGETRequest, httpPOSTRequest, httpPUTRequest, httpPOSTRequestWithHAL } from "../httpRequestHandler";
import API from "../endpoints";
@@ -36,29 +37,22 @@
let responseData = res.data;
const _embedded = responseData['_embedded']; // data._embedded.task is where the task list is.
if (!_embedded || !_embedded['task'] || !responseData['count']) {
- if (responseData['count'] !== undefined && responseData['count'] === 0) {
- const tasks = []
- dispatch(setBPMTaskCount(0));
- dispatch(setBPMTaskList(tasks));
- dispatch(setBPMTaskLoader(false));
- done(null, tasks);
- } else {
- // Display error if the necessary values are unavailable.
- console.log("Error", res);
- dispatch(serviceActionError(res));
- dispatch(setBPMTaskLoader(false));
- }
+ console.log("Error", res);
+ dispatch(setBPMTaskList([]));
+ dispatch(setBPMTaskCount(0));
+ dispatch(serviceActionError(res));
+ dispatch(setBPMTaskLoader(false));
} else {
const taskListFromResponse = _embedded['task']; // Gets the task array
const taskCount = {
count: responseData['count']
};
let taskData = taskListFromResponse;
- if(taskIdToRemove){
- console.log("task----",taskIdToRemove);
+ if (taskIdToRemove) {
+ console.log("task----", taskIdToRemove);
//if the list has the task with taskIdToRemove remove that task and decrement
- if(taskListFromResponse.find((task)=>task.id===taskIdToRemove)){
- taskData=taskListFromResponse.filter( (task)=>task.id!==taskIdToRemove);
+ if (taskListFromResponse.find((task) => task.id === taskIdToRemove)) {
+ taskData = taskListFromResponse.filter((task) => task.id !== taskIdToRemove);
taskCount['count']--; // Count has to be decreased since one task id is removed.
}
}
@@ -69,12 +63,16 @@
}
} else {
console.log("Error", res);
+ dispatch(setBPMTaskList([]));
+ dispatch(setBPMTaskCount(0));
dispatch(serviceActionError(res));
dispatch(setBPMTaskLoader(false));
}
})
.catch((error) => {
console.log("Error", error);
+ dispatch(setBPMTaskList([]));
+ dispatch(setBPMTaskCount(0));
dispatch(serviceActionError(error));
dispatch(setBPMTaskLoader(false));
done(error);
@@ -94,6 +92,7 @@
} else {
console.log("Error", res);
dispatch(serviceActionError(res));
+ dispatch(setBPMProcessList([]));
//dispatch(setBPMTaskLoader(false));
}
})
@@ -139,11 +138,11 @@
//let getReviewerUserListApi = `${API.GET_BPM_USER_LIST}?memberOfGroup=${REVIEWER_GROUP}`;
if(searchType && query){
//getReviewerUserListApi = `${getReviewerUserListApi}&${searchType}=%${query||""}%`
- paramData[searchType]=`%${query}%`;
+ paramData[searchType] = `${query}`;
}
return (dispatch) => {
- httpGETRequest(API.GET_BPM_USER_LIST, paramData, UserService.getToken())
+ httpGETRequest(API.GET_API_USER_LIST, paramData, UserService.getToken())
.then((res) => {
if (res.data) {
dispatch(setBPMUserList(res.data));
@@ -217,7 +216,10 @@
let taskDetail=responses[0].data;
if(responses[1]?.data){
let taskDetailUpdates = responses[1]?.data;
- taskDetail = {...taskDetail,...taskDetailVariableDataFormatter(taskDetailUpdates)};
+ taskDetail = {
+ ...taskDetailVariableDataFormatter(taskDetailUpdates),
+ ...taskDetail,
+ };
}
dispatch(setBPMTaskDetail(taskDetail));
@@ -445,4 +447,3 @@
});
};
};
-
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-web/src/components/ServiceFlow/filter/ServiceTaskFilterListDropDown.js b/apps/forms-flow-ai/forms-flow-web/src/components/ServiceFlow/filter/ServiceTaskFilterListDropDown.js
index f5f5e567..e7569710 100644
--- a/apps/forms-flow-ai/forms-flow-web/src/components/ServiceFlow/filter/ServiceTaskFilterListDropDown.js
+++ b/apps/forms-flow-ai/forms-flow-web/src/components/ServiceFlow/filter/ServiceTaskFilterListDropDown.js
@@ -4,6 +4,8 @@ import {useDispatch, useSelector} from "react-redux";
import {setSelectedBPMFilter, setSelectedTaskID} from "../../../actions/bpmTaskActions";
import {Link} from "react-router-dom";
/*import {Link} from "react-router-dom";*/
+import { useTranslation } from "react-i18next";
+import { MULTITENANCY_ENABLED } from "../../../constants/constants";
const ServiceFlowFilterListDropDown = React.memo(() => {
@@ -11,6 +13,10 @@ const ServiceFlowFilterListDropDown = React.memo(() => {
const filterList = useSelector(state=> state.bpmTasks.filterList);
const isFilterLoading = useSelector(state=> state.bpmTasks.isFilterLoading);
const selectedFilter=useSelector(state=>state.bpmTasks.selectedFilter);
+ const { t } = useTranslation();
+ const tenantKey = useSelector((state) => state.tenants?.tenantId);
+ const redirectUrl = MULTITENANCY_ENABLED ? `/tenant/${tenantKey}/` : "/";
+
const changeFilterSelection = (filter)=>{
dispatch(setSelectedBPMFilter(filter));
@@ -26,7 +32,7 @@ const ServiceFlowFilterListDropDown = React.memo(() => {
changeFilterSelection(filter)}>
{
return (
- No Filters Found
+ {t("No Filters Found")}
)
}
- }
- return <>
- {isFilterLoading? Loading...: renderFilterList()}
+ };
+ return (
+ <>
+ {isFilterLoading ? (
+ {t("Loading")}...
+ ) : (
+ renderFilterList()
+ )}
>
+ );
});
-export default ServiceFlowFilterListDropDown;
+export default ServiceFlowFilterListDropDown;
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-web/src/constants/groupConstants.js b/apps/forms-flow-ai/forms-flow-web/src/constants/groupConstants.js
new file mode 100644
index 00000000..3782d41b
--- /dev/null
+++ b/apps/forms-flow-ai/forms-flow-web/src/constants/groupConstants.js
@@ -0,0 +1,4 @@
+export const GROUPS={
+ applicationsAccess:["/formsflow/access-allow-applications","/formsflow/formsflow-client/access-allow-applications"],
+ viewSubmissionsAccess:["/formsflow/access-allow-submissions"]
+ };
\ No newline at end of file
diff --git a/apps/forms-flow-ai/forms-flow-web/src/containers/NavBar.jsx b/apps/forms-flow-ai/forms-flow-web/src/containers/NavBar.jsx
index 42f231a9..0832ca78 100644
--- a/apps/forms-flow-ai/forms-flow-web/src/containers/NavBar.jsx
+++ b/apps/forms-flow-ai/forms-flow-web/src/containers/NavBar.jsx
@@ -1,34 +1,84 @@
-import React from "react";
+import React, { useEffect, useMemo, useState } from "react";
import {Navbar, Dropdown, Container, Nav, NavDropdown} from "react-bootstrap";
import {Link, useLocation} from "react-router-dom";
import {useDispatch, useSelector} from "react-redux";
import UserService from "../services/UserService";
import {getUserRoleName, getUserRolePermission, getUserInsightsPermission} from "../helper/user";
+import createURLPathMatchExp from "../helper/regExp/pathMatch";
+import { useTranslation } from "react-i18next";
import "./styles.scss";
-import {CLIENT, STAFF_REVIEWER, APPLICATION_NAME, STAFF_DESIGNER} from "../constants/constants";
+import {CLIENT, STAFF_REVIEWER, APPLICATION_NAME, STAFF_DESIGNER, MULTITENANCY_ENABLED} from "../constants/constants";
import ServiceFlowFilterListDropDown from "../components/ServiceFlow/filter/ServiceTaskFilterListDropDown";
import {push} from "connected-react-router";
+import i18n from "../resourceBundles/i18n";
+import { setLanguage } from "../actions/languageSetAction";
+import { updateUserlang } from "../apiManager/services/userservices";
+
+import { fetchSelectLanguages } from "../apiManager/services/languageServices";
const NavBar = React.memo(() => {
const isAuthenticated = useSelector((state) => state.user.isAuthenticated);
const location = useLocation();
const { pathname } = location;
const user = useSelector((state) => state.user.userDetail);
+ const lang = useSelector((state) => state.user.lang);
const userRoles = useSelector((state) => state.user.roles);
const showApplications= useSelector((state) => state.user.showApplications);
+ const applicationTitle = useSelector(
+ (state) => state.tenants?.tenantData?.details?.applicationTitle
+ );
+ const tenantKey = useSelector((state) => state.tenants?.tenantId);
+ const formTenant = useSelector((state)=>state.form?.form?.tenantKey);
+ const baseUrl = MULTITENANCY_ENABLED ? `/tenant/${tenantKey}/` : "/";
+ /**
+ * For anonymous forms the only way to identify the tenant is through the
+ * form data with current implementation. To redirect to the correact tenant
+ * we will use form as the data source for the tenantKey
+ */
+
+ const [loginUrl, setLoginUrl] = useState(baseUrl);
+ const selectLanguages = useSelector((state) => state.user.selectLanguages);
const dispatch = useDispatch();
const logoPath = "/logo.svg";
- const appName = APPLICATION_NAME;
+ const getAppName = useMemo(
+ () => () => {
+ if (!MULTITENANCY_ENABLED) {
+ return APPLICATION_NAME;
+ }
+ // TODO: Need a propper fallback component prefered a skeleton.
+ return applicationTitle || "";
+ },
+ [MULTITENANCY_ENABLED, applicationTitle]
+ );
+ const appName = getAppName();
+ const { t } = useTranslation();
+ useEffect(()=>{
+ if(!isAuthenticated && formTenant && MULTITENANCY_ENABLED){
+ setLoginUrl(`/tenant/${formTenant}/`);
+ }
+ },[isAuthenticated, formTenant]);
+
+ useEffect(() => {
+ dispatch(fetchSelectLanguages());
+ }, [dispatch]);
+ useEffect(() => {
+ i18n.changeLanguage(lang);
+ }, [lang]);
+
+ const handleOnclick = (selectedLang) => {
+ dispatch(setLanguage(selectedLang));
+ dispatch(updateUserlang(selectedLang));
+ };
const logout = () => {
- dispatch(push(`/`));
- UserService.userLogout();
- }
+ dispatch(push(baseUrl));
+ UserService.userLogout();
+ };
const goToTask = () => {
- dispatch(push(`/task`));
- }
+ dispatch(push(`${baseUrl}task`));
+ };
return (
@@ -67,61 +117,61 @@ const NavBar = React.memo(() => {
{isAuthenticated?
- }
- id="task-dropdown"
- className={`main-nav nav-item taskDropdown
- ${pathname.match(/^\/task/) ? "" : "inactive-tab"}`
- }
- onClick={goToTask}
- >
-
- :null}
+ /> */}
+
+
+ {t("Tasks")}
+
+ )
+ :null
+ }
{getUserRolePermission(userRoles, STAFF_REVIEWER) ?
-
-
+
-
- Dashboards
-
-
- }
- id="dashboard-dropdown"
- className={`main-nav nav-item
- ${pathname.match(/^\/metrics/) || pathname.match(/^\/insights/) ? "" : "inactive-tab-dropdown"}`
- }
+
-
-
-
-
- Metrics
-
-
- {
- getUserInsightsPermission() &&
-
-
-
- Insights
-
-
- }
- :null}
+ {t("Dashboards")}
+
+ )
+ :null
+ }