mirror of
https://github.com/HWienhold/indu-reboot.git
synced 2026-02-07 00:07:44 +00:00
prepare for js code injection
This commit is contained in:
parent
ee01e122a8
commit
84470b4f4b
40
js-injection-service/pom.xml
Normal file
40
js-injection-service/pom.xml
Normal file
@ -0,0 +1,40 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.indu</groupId>
|
||||
<artifactId>indu-flow-parent</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>js-injection-service</artifactId>
|
||||
<name>js-injection-service</name>
|
||||
<description>JS Servic for User Injections</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-gateway</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.javadelight</groupId>
|
||||
<artifactId>delight-nashorn-sandbox</artifactId>
|
||||
<version>0.3.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -0,0 +1,13 @@
|
||||
package com.indu.jsinjectionservice;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class JsInjectionApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(JsInjectionApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package com.indu.jsinjectionservice.controller;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.indu.jsinjectionservice.dto.JsExectutionRequest;
|
||||
import com.indu.jsinjectionservice.service.JsExecutionService;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/js")
|
||||
@RequiredArgsConstructor
|
||||
public class JsExecutionController {
|
||||
|
||||
private final JsExecutionService service;
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<?> execute(@Valid @RequestBody JsExectutionRequest request) {
|
||||
try {
|
||||
service.executeInSandbox(request);
|
||||
return new ResponseEntity<Object>(HttpStatus.OK);
|
||||
} catch (Exception e) {
|
||||
return new ResponseEntity<String>( e.getLocalizedMessage(),HttpStatus.I_AM_A_TEAPOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
package com.indu.jsinjectionservice.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class JsExectutionRequest {
|
||||
|
||||
@NonNull
|
||||
private String script;
|
||||
@NonNull
|
||||
private String callerId;
|
||||
@NonNull
|
||||
private String endpoint;
|
||||
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
package com.indu.jsinjectionservice.service;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.indu.jsinjectionservice.dto.JsExectutionRequest;
|
||||
|
||||
import delight.nashornsandbox.NashornSandbox;
|
||||
import delight.nashornsandbox.exceptions.ScriptCPUAbuseException;
|
||||
import delight.nashornsandbox.internal.NashornSandboxImpl;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class JsExecutionService {
|
||||
|
||||
private final JsGenerationService generator;
|
||||
|
||||
public void executeInSandbox(@Valid JsExectutionRequest request) throws ScriptCPUAbuseException, ScriptException {
|
||||
NashornSandbox sandbox = initializeSandbox();
|
||||
sandbox.eval( generator.getCallerIdGetter(request.getCallerId()));
|
||||
sandbox.eval( generator.getEndpointGetter(request.getEndpoint()));
|
||||
sandbox.eval( generator.getFetchCallerFunction());
|
||||
}
|
||||
|
||||
private NashornSandbox initializeSandbox() {
|
||||
// NashornSandbox sandbox = NashornSandboxes.create();
|
||||
NashornSandbox sandbox = new NashornSandboxImpl() {
|
||||
@Override
|
||||
public Object eval(String js) throws ScriptCPUAbuseException, ScriptException {
|
||||
log.info(String.format("Running command \"%s\"", js));
|
||||
return super.eval(js);
|
||||
}
|
||||
};
|
||||
|
||||
sandbox.setMaxCPUTime(100);
|
||||
sandbox.setMaxMemory(50 * 1024);
|
||||
sandbox.allowNoBraces(false);
|
||||
sandbox.setMaxPreparedStatements(30);
|
||||
sandbox.setExecutor(Executors.newSingleThreadExecutor());
|
||||
|
||||
return sandbox;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
package com.indu.jsinjectionservice.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class JsGenerationService {
|
||||
|
||||
// TODO: maybe add update parent whatever ...
|
||||
public String getEndpointGetter(String api) {
|
||||
return getFunction("getEndpoint", ret(api));
|
||||
}
|
||||
|
||||
public String getCallerIdGetter(String id) {
|
||||
return getFunction("getCallerId", ret(id));
|
||||
}
|
||||
|
||||
public String getFetchCallerFunction() {
|
||||
// for now assume the other functions already added...
|
||||
return "async " + getFunction("getCaller", getFetchBody());
|
||||
}
|
||||
|
||||
private static String getFetchBody() {
|
||||
StringBuilder body = new StringBuilder();
|
||||
body.append("const response = await fetch( getEndpoint() );\n");
|
||||
body.append("cost data = await response.json();\n");
|
||||
return trycatch(body.toString() + ret("data"));
|
||||
|
||||
}
|
||||
|
||||
private static String getFunction (String name, String body, String... args) {
|
||||
StringBuilder functionCode = new StringBuilder();
|
||||
functionCode.append("function " + name);
|
||||
functionCode.append("(" + String.join(", ", args ) +")");
|
||||
functionCode.append("{" + body +"}");
|
||||
return functionCode.toString();
|
||||
}
|
||||
|
||||
private static String ret(String var) {
|
||||
return "return " + var + ";";
|
||||
}
|
||||
|
||||
private static String trycatch ( String tryBody, String catchBody, String finallyBody) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(" try { " + tryBody + " } ");
|
||||
builder.append((" catch (error) { " + catchBody) == null ? "console.error(error);" : catchBody+ " } ");
|
||||
if ( finallyBody != null) {
|
||||
builder.append("finally { " + finallyBody + " } ");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static String trycatch ( String tryBody, String catchBody) {
|
||||
return trycatch(tryBody, catchBody, null);
|
||||
}
|
||||
|
||||
private static String trycatch ( String tryBody) {
|
||||
return trycatch(tryBody, null);
|
||||
}
|
||||
}
|
||||
1
pom.xml
1
pom.xml
@ -24,6 +24,7 @@
|
||||
<module>workflow-template-service</module>
|
||||
<module>com.indu.exceptionservice</module>
|
||||
<module>exception-service</module>
|
||||
<module>js-injection-service</module>
|
||||
</modules>
|
||||
<properties>
|
||||
<org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
|
||||
|
||||
@ -81,7 +81,6 @@ public class TaskController {
|
||||
return service.setParentId(id, parentId);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping(path="/byTemplate")
|
||||
public TaskResponse createTaskFromTemplate(@RequestBody TaskTemplateDto template) {
|
||||
return null;
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
package com.indu.taskservice.dto;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
public class JsScriptDto {
|
||||
|
||||
@NonNull
|
||||
private String script;
|
||||
@NonNull
|
||||
private String callerId;
|
||||
@NonNull
|
||||
@Builder.Default
|
||||
private String endpoint="/api/tasks";
|
||||
|
||||
}
|
||||
@ -21,4 +21,5 @@ public class TaskResponse {
|
||||
private String afterTaskId;
|
||||
private String parentId;
|
||||
private Map<String, String> data;
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.indu.taskservice.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.mongodb.core.index.Indexed;
|
||||
@ -30,6 +31,7 @@ public class TaskTemplate {
|
||||
@Builder.Default
|
||||
private boolean checkPreviousBeforeActivate = true;
|
||||
|
||||
private Map<TaskState, List<String>> scriptActions;
|
||||
private AbortAction abortAction;
|
||||
private Map<String, String> requiredFieldOnFinish; // for now just requiredFields => pattern
|
||||
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
package com.indu.taskservice.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import com.indu.taskservice.dto.JsScriptDto;
|
||||
import com.indu.taskservice.model.Task;
|
||||
import com.indu.taskservice.model.TaskState;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class JsExecutionService {
|
||||
private final WebClient.Builder webClientBuilder;
|
||||
|
||||
public void handleScriptAction(Task task, TaskState state) {
|
||||
if( !task.getTemplate().getScriptActions().containsKey(state) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
task.getTemplate().getScriptActions().get(state).stream().forEach(s->executeScript(task,s));
|
||||
|
||||
}
|
||||
|
||||
private void executeScript(Task task, String s) {
|
||||
webClientBuilder.build().post()
|
||||
.uri("http://localhost:8080/api/js")
|
||||
.bodyValue(JsScriptDto.builder()
|
||||
.callerId(task.getId())
|
||||
.script(s))
|
||||
.retrieve()
|
||||
.bodyToMono(Object.class)
|
||||
.doOnNext(res->log.info(String.format("Successfully run scrip %s", res) ))
|
||||
.doOnError(res->log.error(String.format("Scriptrun failed: %s", res.getMessage())))
|
||||
.block(); // prevent parallel execution of diff scripts - they might all try to change the current task
|
||||
}
|
||||
|
||||
}
|
||||
@ -24,6 +24,7 @@ public class TaskFlowService {
|
||||
|
||||
private final TaskService taskService;
|
||||
private final TaskRepository repository;
|
||||
private final JsExecutionService jsService;
|
||||
|
||||
public Task updateState(String id, @Valid TaskStateRequest taskRequest) {
|
||||
Task task = taskService.getTaskById(id);
|
||||
@ -40,21 +41,33 @@ public class TaskFlowService {
|
||||
task.setReadyTime(new Date());
|
||||
}
|
||||
repository.save(task);
|
||||
handleTransitionAction(task, taskRequest.getState());
|
||||
return task;
|
||||
}
|
||||
|
||||
public Task activateTask(String id, @Valid EditorData editor) {
|
||||
Task task = taskService.getTaskById(id);
|
||||
if(task.getTemplate().isCheckPreviousBeforeActivate() && !previousTasksDone(task)) {
|
||||
log.error(String.format("Activation of task %s ot allowed. There seem to be previous open task. Aborting", id));
|
||||
log.error(String.format("Activation of task %s not allowed. There seem to be previous open task. Aborting", id));
|
||||
return task;
|
||||
}
|
||||
TaskState state = task.getTemplate().getActivationState();
|
||||
// TODO: validate is WAITING (?)
|
||||
task.setState(state);
|
||||
task.setEditor(editor);
|
||||
repository.save(task);
|
||||
return task;
|
||||
if(task.getState().equals(state)) {
|
||||
log.error(String.format("State of %s already %s. sth. fishy. Aborting", id, state));
|
||||
return task;
|
||||
}
|
||||
|
||||
return updateState(id,
|
||||
TaskStateRequest.builder().editor(editor).state(state).build()
|
||||
);
|
||||
}
|
||||
|
||||
// TBD: precedece? doesnt matter for the moment
|
||||
public void handleTransitionAction(Task task, TaskState state) {
|
||||
jsService.handleScriptAction(task, state);
|
||||
if ( state.equals(TaskState.ABORT)) {
|
||||
// AbortAction
|
||||
}
|
||||
}
|
||||
|
||||
private boolean previousTasksDone(Task task) {
|
||||
|
||||
@ -0,0 +1,78 @@
|
||||
package com.indu.tasktemplateservice.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.indu.tasktemplateservice.dto.MultiScriptDto;
|
||||
import com.indu.tasktemplateservice.dto.SingleScriptDto;
|
||||
import com.indu.tasktemplateservice.dto.TaskTemplateDto;
|
||||
import com.indu.tasktemplateservice.model.CustomAction;
|
||||
import com.indu.tasktemplateservice.model.TaskState;
|
||||
import com.indu.tasktemplateservice.service.TaskActionService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(path = "/api/template/tasks")
|
||||
@RequiredArgsConstructor
|
||||
public class StateChangeController {
|
||||
|
||||
private final TaskActionService service;
|
||||
|
||||
@GetMapping(path="/{id}/action/{action}")
|
||||
public Object getStateTransitionActions(@PathVariable String id, @PathVariable CustomAction action) {
|
||||
return service.getStateTransitionAction(id, action);
|
||||
}
|
||||
|
||||
@PostMapping(path="/{id}/action/SCRIPT")
|
||||
public MultiScriptDto setScriptAction(@PathVariable String id, @RequestBody MultiScriptDto scripts) {
|
||||
return service.setScriptAction(id, scripts);
|
||||
}
|
||||
|
||||
@PutMapping(path="/{id}/action/SCRIPT")
|
||||
public MultiScriptDto setScriptAction(@PathVariable String id, @RequestBody SingleScriptDto script) {
|
||||
return service.addScriptAction(id, script);
|
||||
}
|
||||
|
||||
@PostMapping(path="/{id}/action/{action}")
|
||||
public Object getStateTransitionActions(@PathVariable String id, @PathVariable CustomAction action, @RequestBody TaskTemplateDto foo) {
|
||||
return service.getStateTransitionAction(id, action);
|
||||
}
|
||||
|
||||
@DeleteMapping(path="/{id}/action/SCRIPT/{state}/{i}")
|
||||
public MultiScriptDto removeScriptAction(@PathVariable String id, @PathVariable TaskState state, @PathVariable int i) {
|
||||
service.removeScriptAction(id, state, i);
|
||||
return service.getStateTransitionScriptAction(id);
|
||||
}
|
||||
|
||||
@GetMapping(path="/{id}/action/SCRIPT/{state}/{i}")
|
||||
public ResponseEntity<String> getSingleScriptAction(@PathVariable String id, @PathVariable TaskState state, @PathVariable int i) {
|
||||
return service.getSingleScriptAction(id, state, i) == null
|
||||
? new ResponseEntity(HttpStatus.NOT_FOUND)
|
||||
: new ResponseEntity<String>(service.getSingleScriptAction(id, state, i), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@GetMapping(path="/{id}/action/SCRIPT/{state}")
|
||||
public ResponseEntity<List<String>> getSingleScriptAction(@PathVariable String id, @PathVariable TaskState state) {
|
||||
return service.getScriptActionForState(id, state) == null
|
||||
? new ResponseEntity(HttpStatus.NOT_FOUND)
|
||||
: new ResponseEntity<List<String>>(service.getScriptActionForState(id, state), HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
||||
@DeleteMapping(path="/{id}/action/SCRIPT/{state}")
|
||||
public MultiScriptDto removeScriptAction(@PathVariable String id, @PathVariable TaskState state) {
|
||||
service.removeScriptAction(id, state);
|
||||
return service.getStateTransitionScriptAction(id);
|
||||
}
|
||||
}
|
||||
@ -35,7 +35,12 @@ public class TaskTemplateController {
|
||||
|
||||
@GetMapping(path = "/{id}")
|
||||
public TaskTemplateDto getTaskTemplateById(@PathVariable String id) {
|
||||
return service.getTaskTemplateById(id);
|
||||
return service.getTaskTemplateDtoById(id);
|
||||
}
|
||||
|
||||
@PostMapping(path = "/{id}")
|
||||
public TaskTemplateDto updateTaskTemplate(@PathVariable String id, @RequestBody TaskTemplateDto request) {
|
||||
return service.updateTaskTemplateDto(id, request);
|
||||
}
|
||||
|
||||
@GetMapping(params = "group_id")
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
package com.indu.tasktemplateservice.dto;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.indu.tasktemplateservice.model.TaskState;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class MultiScriptDto extends HashMap<TaskState, List<String>> {
|
||||
public MultiScriptDto(MultiScriptDto toCopy) {
|
||||
for ( TaskState state : toCopy.keySet()) {
|
||||
put(state, toCopy.get(state));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
package com.indu.tasktemplateservice.dto;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.indu.tasktemplateservice.model.TaskState;
|
||||
|
||||
public class SingleScriptDto extends HashMap<TaskState, String> {}
|
||||
@ -26,4 +26,6 @@ public class TaskTemplateDto {
|
||||
private boolean checkPreviousDoneBeforeActivate;
|
||||
// private AbortAction abortAction;
|
||||
private Map<String, String> requiredFieldOnFinish;
|
||||
|
||||
private MultiScriptDto scriptActions;
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import lombok.Getter;
|
||||
public enum AbortAction {
|
||||
ABORT_WORKFLOW("abort_workflow"),
|
||||
STEP_BACK("step_back"),
|
||||
// RESTART i.e. clone for now
|
||||
RESTART_WORKFLOW("restart_workflow");
|
||||
|
||||
private final String value;
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
package com.indu.tasktemplateservice.model;
|
||||
|
||||
public class Action {
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package com.indu.tasktemplateservice.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum CustomAction {
|
||||
CALL("call"),
|
||||
SCRIPT("script");
|
||||
|
||||
private final String value;
|
||||
}
|
||||
@ -6,6 +6,7 @@ import org.springframework.data.mongodb.core.index.Indexed;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.indu.tasktemplateservice.dto.MultiScriptDto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
@ -37,4 +38,7 @@ public class TaskTemplate {
|
||||
// TODO -> i think it might be better to let workflow handle post action? maybe just notify -> TBD
|
||||
// private Map<TaskState, List< Action> > postAction;
|
||||
|
||||
// private Map<TaskState, List< Pair<CustomAction, List<String> > > > actions;
|
||||
|
||||
private MultiScriptDto scriptActions;
|
||||
}
|
||||
|
||||
@ -0,0 +1,117 @@
|
||||
package com.indu.tasktemplateservice.service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.indu.tasktemplateservice.dto.MultiScriptDto;
|
||||
import com.indu.tasktemplateservice.dto.SingleScriptDto;
|
||||
import com.indu.tasktemplateservice.dto.TaskTemplateDto;
|
||||
import com.indu.tasktemplateservice.model.CustomAction;
|
||||
import com.indu.tasktemplateservice.model.TaskState;
|
||||
import com.indu.tasktemplateservice.model.TaskTemplate;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class TaskActionService {
|
||||
|
||||
private final TaskTemplateService templateService;
|
||||
|
||||
public MultiScriptDto getStateTransitionScriptAction(String id) {
|
||||
TaskTemplate task = templateService.getTaskTemplateById(id);
|
||||
if(task.getScriptActions() == null) {
|
||||
return new MultiScriptDto();
|
||||
}
|
||||
return task.getScriptActions();
|
||||
}
|
||||
|
||||
public Object getStateTransitionCallAction(String id) {
|
||||
//TDB
|
||||
TaskTemplate task = templateService.getTaskTemplateById(id);
|
||||
return task;
|
||||
}
|
||||
|
||||
public Object getStateTransitionAction(String id, CustomAction action) {
|
||||
if ( CustomAction.SCRIPT.equals(action)) {
|
||||
return getStateTransitionScriptAction(id);
|
||||
}
|
||||
if ( CustomAction.CALL.equals(action)) {
|
||||
return getStateTransitionCallAction(id);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public MultiScriptDto setScriptAction(String id, MultiScriptDto scripts) {
|
||||
TaskTemplateDto taskTemplateDto = templateService.getTaskTemplateDtoById(id);
|
||||
taskTemplateDto.setScriptActions(scripts);
|
||||
return templateService.updateTaskTemplate(id, taskTemplateDto).getScriptActions();
|
||||
}
|
||||
|
||||
public MultiScriptDto addScriptAction(String id, SingleScriptDto script) {
|
||||
TaskTemplateDto taskTemplateDto = templateService.getTaskTemplateDtoById(id);
|
||||
for ( TaskState state : script.keySet() ) {
|
||||
if(!taskTemplateDto.getScriptActions().containsKey(state)) {
|
||||
taskTemplateDto.getScriptActions().put(state, new ArrayList<String>());
|
||||
}
|
||||
taskTemplateDto.getScriptActions().get(state).add(script.get(state));
|
||||
}
|
||||
return templateService.updateTaskTemplate(id, taskTemplateDto).getScriptActions();
|
||||
}
|
||||
|
||||
public void removeScriptAction(String id, TaskState state, int i) {
|
||||
TaskTemplateDto taskTemplateDto = templateService.getTaskTemplateDtoById(id);
|
||||
if(!taskTemplateDto.getScriptActions().containsKey(state)) {
|
||||
log.warn(String.format("Tried to delete script actions for state %s, but no actions found for this state. Aborting", state));
|
||||
return;
|
||||
}
|
||||
if(taskTemplateDto.getScriptActions().get(state).size() <= i ) {
|
||||
log.warn(String.format("Tried to delete script action no %s for state %s, but only %s actions found for this state. Aborting",
|
||||
i+1, state, taskTemplateDto.getScriptActions().size()));
|
||||
return;
|
||||
}
|
||||
|
||||
taskTemplateDto.getScriptActions().get(state).remove(i);
|
||||
if (taskTemplateDto.getScriptActions().get(state).size() == 0) {
|
||||
taskTemplateDto.getScriptActions().remove(state);
|
||||
}
|
||||
templateService.updateTaskTemplate(id, taskTemplateDto);
|
||||
}
|
||||
|
||||
public void removeScriptAction(String id, TaskState state) {
|
||||
TaskTemplateDto taskTemplateDto = templateService.getTaskTemplateDtoById(id);
|
||||
if(!taskTemplateDto.getScriptActions().containsKey(state)) {
|
||||
log.warn(String.format("Tried to delete script actions for state %s, but no actions found for this state. Aborting", state));
|
||||
return;
|
||||
}
|
||||
taskTemplateDto.getScriptActions().remove(state);
|
||||
templateService.updateTaskTemplate(id, taskTemplateDto);
|
||||
}
|
||||
|
||||
public String getSingleScriptAction(String id, TaskState state, int i) {
|
||||
List<String> stateAction = getScriptActionForState(id, state);
|
||||
if(stateAction == null) {
|
||||
return null;
|
||||
}
|
||||
if(stateAction.size() <= i ) {
|
||||
log.warn(String.format("Tried to get script action no %s for state %s, but only %s actions found for this state.",
|
||||
i+1, state, stateAction.size()));
|
||||
return null;
|
||||
}
|
||||
return stateAction.get(i);
|
||||
}
|
||||
|
||||
public List<String> getScriptActionForState(String id, TaskState state) {
|
||||
TaskTemplateDto taskTemplateDto = templateService.getTaskTemplateDtoById(id);
|
||||
if(!taskTemplateDto.getScriptActions().containsKey(state)) {
|
||||
log.warn(String.format("Tried to script actions for state %s, but no actions found.", state));
|
||||
return null;
|
||||
}
|
||||
return taskTemplateDto.getScriptActions().get(state);
|
||||
}
|
||||
|
||||
}
|
||||
@ -38,11 +38,13 @@ public class TaskTemplateService {
|
||||
return repository.findAll().stream().map(mapper::taskTemplateToDto).toList();
|
||||
}
|
||||
|
||||
public TaskTemplateDto getTaskTemplateById(String id) {
|
||||
return mapper.taskTemplateToDto(
|
||||
repository.findById(id)
|
||||
.orElseThrow(() -> new ObjectWithUniqueFieldNotFoundException("BOID", id, getClass().getName()))
|
||||
);
|
||||
public TaskTemplateDto getTaskTemplateDtoById(String id) {
|
||||
return mapper.taskTemplateToDto(getTaskTemplateById(id));
|
||||
}
|
||||
|
||||
public TaskTemplate getTaskTemplateById(String id) {
|
||||
return repository.findById(id)
|
||||
.orElseThrow(() -> new ObjectWithUniqueFieldNotFoundException("BOID", id, getClass().getName()));
|
||||
}
|
||||
|
||||
public TaskTemplateDto getTaskTemplateDtoByName(String name) {
|
||||
@ -52,4 +54,15 @@ public class TaskTemplateService {
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public TaskTemplate updateTaskTemplate(String id, TaskTemplateDto request) {
|
||||
TaskTemplate template = getTaskTemplateById(id);
|
||||
mapper.updateTaskTemplateFromRequest(request, template);
|
||||
repository.save(template);
|
||||
return template;
|
||||
}
|
||||
|
||||
public TaskTemplateDto updateTaskTemplateDto(String id, TaskTemplateDto request) {
|
||||
return mapper.taskTemplateToDto(updateTaskTemplate(id, request));
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,6 @@ public class WorkflowTemplateDto {
|
||||
private String id;
|
||||
private String identiferPrefix;
|
||||
private String name;
|
||||
private List<String> tasks;
|
||||
private List<String> workflows;
|
||||
private List<String> taskTemplateIds;
|
||||
private List<String> subWorkflowTemplateIds;
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package com.indu.workflowservice.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
@ -11,4 +13,6 @@ public class WorkflowTemplate {
|
||||
private String id;
|
||||
private String identiferPrefix;
|
||||
private String name;
|
||||
private List<String> taskTemplateIds;
|
||||
private List<String> subWorkflowTemplateIds;
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ public class WorkflowService {
|
||||
.taskIds(new ArrayList<String>())
|
||||
.build();
|
||||
log.info(String.format("Added asy fields. Workflow has form %s. Adding tasks", workflow));
|
||||
addTasksToWorkflow(workflow, template.getTasks());
|
||||
addTasksToWorkflow(workflow, template.getTaskTemplateIds());
|
||||
addSubFlowsToWorkflow(workflow);
|
||||
|
||||
return workflow;
|
||||
@ -87,6 +87,7 @@ public class WorkflowService {
|
||||
|
||||
public Workflow createNewWorkflowByTemplateId(String id) {
|
||||
log.info("fetching template for wf creation....");
|
||||
log.info(String.format("Feched template %s", templateRepo.getById(id)));
|
||||
return createNewWorkflow(templateRepo.getById(id));
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,10 +17,12 @@ import com.indu.workflowtemplateservice.service.WorkflowTemplateService;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(path = "/api/template/workflow")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class WorkflowTemplateController {
|
||||
|
||||
private final WorkflowTemplateService service;
|
||||
@ -32,6 +34,7 @@ public class WorkflowTemplateController {
|
||||
|
||||
@GetMapping
|
||||
public List<WorkflowTemplateResponse> getTemplates() {
|
||||
log.info("Got getAll call");
|
||||
return service.getAllWorkflowTemplates();
|
||||
}
|
||||
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
package com.indu.workflowtemplateservice.dto;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import com.indu.workflowtemplateservice.model.TaskTemplate;
|
||||
import com.indu.workflowtemplateservice.model.WorkflowTemplate;
|
||||
|
||||
@Mapper
|
||||
public interface WorkflowMapper {
|
||||
|
||||
WorkflowMapper instance = Mappers.getMapper(WorkflowMapper.class);
|
||||
|
||||
WorkflowTemplate requestToWorkflow(WorkflowTemplateRequest request);
|
||||
WorkflowTemplateResponse workflowToResponse(WorkflowTemplate templateObject);
|
||||
|
||||
|
||||
default List<TaskTemplate> map(List<String> value){
|
||||
return new ArrayList<TaskTemplate>();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
package com.indu.workflowtemplateservice.dto;
|
||||
|
||||
import org.mapstruct.AfterMapping;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.MappingTarget;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import com.indu.workflowtemplateservice.model.WorkflowTemplate;
|
||||
|
||||
@Mapper
|
||||
public interface WorkflowTemplateMapper {
|
||||
|
||||
WorkflowTemplateMapper instance = Mappers.getMapper(WorkflowTemplateMapper.class);
|
||||
|
||||
WorkflowTemplate map(WorkflowTemplateRequest request);
|
||||
WorkflowTemplateResponse map(WorkflowTemplate templateObject);
|
||||
WorkflowTemplateRequest mapToRequest(WorkflowTemplate template);
|
||||
|
||||
|
||||
@AfterMapping
|
||||
public default void addSubFlowFromTemplate1(WorkflowTemplate template, @MappingTarget WorkflowTemplateRequest request) {
|
||||
if ( template.getSubWorkflow() == null) {
|
||||
return;
|
||||
}
|
||||
request.setSubWorkflowId(
|
||||
template.getSubWorkflow().stream().map(WorkflowTemplate::getId).toList()
|
||||
);
|
||||
}
|
||||
|
||||
@AfterMapping
|
||||
public default void addSubFlowFromRequest(WorkflowTemplateRequest request, @MappingTarget WorkflowTemplate templateObject) {
|
||||
if ( request.getSubWorkflowId() == null) {
|
||||
return;
|
||||
}
|
||||
templateObject.setSubWorkflow(
|
||||
request.getSubWorkflowId().stream().map(id -> WorkflowTemplate.builder().id(id).build()).toList()
|
||||
);
|
||||
}
|
||||
|
||||
@AfterMapping
|
||||
public default void addSubFlowFromTemplate(WorkflowTemplate templateObject,@MappingTarget WorkflowTemplateResponse response ) {
|
||||
if (templateObject.getSubWorkflow() == null) {
|
||||
return;
|
||||
}
|
||||
response.setSubWorkflowTemplateIds(templateObject.getSubWorkflow().stream().map(WorkflowTemplate::getId).toList());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -23,7 +23,7 @@ public class WorkflowTemplateRequest {
|
||||
|
||||
// TODO: allow to be added direclty, for now tasks must be added bf and added here via id (cf. WorkflowTemplateResponse as well)
|
||||
private List<String> tasksTemplateIds;
|
||||
private List<String> workflowTemplateIds;
|
||||
private List<String> subWorkflowId;
|
||||
|
||||
|
||||
// private Map<String, String> requiredFieldOnFinish; // for now just requiredFields => pattern
|
||||
|
||||
@ -22,5 +22,6 @@ public class WorkflowTemplateResponse {
|
||||
private String name; // unique identifier for sequence
|
||||
// Mostly bTaskTemplate not used - for now fetch by hand whenever needed
|
||||
// private List<TaskTemplate> tasks;
|
||||
private List<String> tasks;
|
||||
private List<String> tasksTemplateIds;
|
||||
private List<String> subWorkflowTemplateIds;
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package com.indu.workflowtemplateservice.model;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.mongodb.core.index.Indexed;
|
||||
import org.springframework.data.mongodb.core.mapping.DBRef;
|
||||
import org.springframework.data.mongodb.core.mapping.Document;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
@ -26,11 +27,11 @@ public class WorkflowTemplate {
|
||||
@Indexed(unique = true)
|
||||
private String name; // unique identifier for sequence
|
||||
// private List<TaskTemplate> taskTemplates; //ids -> Expand????#
|
||||
private List<String> taskTemplatesIds;
|
||||
private List<String> tasksTemplateIds;
|
||||
|
||||
|
||||
// @DBRef(lazy=true)
|
||||
// private List<WorkflowTemplate> subWorkflow;
|
||||
@DBRef(lazy=true)
|
||||
private List<WorkflowTemplate> subWorkflow;
|
||||
//
|
||||
// private String parent_id;
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
@Slf4j
|
||||
public class WorkflowTemplateMapper {
|
||||
public class WorkflowTemplateMapperManual {
|
||||
private final TaskTemplateRepository taskTemplateRepo;
|
||||
|
||||
public WorkflowTemplateRequest mapToRequest(WorkflowTemplate template) {
|
||||
@ -21,7 +21,7 @@ public class WorkflowTemplateMapper {
|
||||
.name(template.getName())
|
||||
.id(template.getId())
|
||||
.identiferPrefix(template.getIdentiferPrefix())
|
||||
.tasksTemplateIds(template.getTaskTemplatesIds())
|
||||
.tasksTemplateIds(template.getTasksTemplateIds())
|
||||
// .tasksTemplateIds(template.getTaskTemplates().stream().map(TaskTemplate::getId).toList())
|
||||
.build();
|
||||
}
|
||||
@ -31,7 +31,7 @@ public class WorkflowTemplateMapper {
|
||||
.name(template.getName())
|
||||
.id(template.getId())
|
||||
.identiferPrefix(template.getIdentiferPrefix())
|
||||
.tasks(template.getTaskTemplatesIds())
|
||||
.tasksTemplateIds(template.getTasksTemplateIds())
|
||||
// .tasks(template.getTaskTemplatesIds().stream().map(taskTemplateRepo::getById).toList())
|
||||
.build();
|
||||
}
|
||||
@ -43,7 +43,7 @@ public class WorkflowTemplateMapper {
|
||||
.identiferPrefix(request.getIdentiferPrefix())
|
||||
.name(request.getName())
|
||||
.id(request.getId())
|
||||
.taskTemplatesIds(request.getTasksTemplateIds())
|
||||
.tasksTemplateIds(request.getTasksTemplateIds())
|
||||
// .taskTemplates(request.getTasksTemplateIds().stream().map(taskTemplateRepo::getById).toList() )
|
||||
.build();
|
||||
}
|
||||
@ -5,6 +5,7 @@ import java.util.List;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.indu.exceptionservice.exception.NameAlreadyTakenException;
|
||||
import com.indu.workflowtemplateservice.dto.WorkflowTemplateMapper;
|
||||
import com.indu.workflowtemplateservice.dto.WorkflowTemplateRequest;
|
||||
import com.indu.workflowtemplateservice.dto.WorkflowTemplateResponse;
|
||||
import com.indu.workflowtemplateservice.model.WorkflowTemplate;
|
||||
@ -46,17 +47,12 @@ public class WorkflowTemplateService {
|
||||
return mapper.map(upsertEmptyTemplate(request));
|
||||
}
|
||||
|
||||
//TODO: needed?
|
||||
public WorkflowTemplateRequest initializeTemplate(@Valid WorkflowTemplateRequest request) {
|
||||
return mapper.mapToRequest(upsertEmptyTemplate(request));
|
||||
}
|
||||
|
||||
public WorkflowTemplate findById(String id) {
|
||||
return repository.findById(id).orElseThrow(() -> new NotFoundException("did not find required wf template"));
|
||||
}
|
||||
|
||||
public List<WorkflowTemplateResponse> getAllWorkflowTemplates() {
|
||||
return repository.findAll().stream().map(mapper::map).toList();
|
||||
return repository.findAll().stream().map(WorkflowTemplateMapper.instance::map).toList();
|
||||
}
|
||||
|
||||
public WorkflowTemplateResponse getWorkflowById(String id) {
|
||||
@ -68,7 +64,7 @@ public class WorkflowTemplateService {
|
||||
}
|
||||
|
||||
public WorkflowTemplate addTaskTemplateToWorkflowTemplate(WorkflowTemplate template, String templateTask) {
|
||||
template.getTaskTemplatesIds().add(templateTask);
|
||||
template.getTasksTemplateIds().add(templateTask);
|
||||
return template;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user