diff --git a/application-engine/pom.xml b/application-engine/pom.xml
index a9669b0e11..d63f7f0177 100644
--- a/application-engine/pom.xml
+++ b/application-engine/pom.xml
@@ -270,18 +270,6 @@
${junit-jupiter.version}
test
-
- org.junit.jupiter
- junit-jupiter-api
- ${junit-jupiter.version}
- test
-
-
- org.junit.jupiter
- junit-jupiter-engine
- ${junit-jupiter.version}
- test
-
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/DataService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/DataService.java
index b7eb4d4855..672a229447 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/DataService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/DataService.java
@@ -71,6 +71,8 @@ public class DataService implements IDataService {
public static final int MONGO_ID_LENGTH = 24;
+ private static final Set setDataForbiddenFieldTypes = Set.of(FieldType.TASK_REF, FieldType.CASE_REF);
+
@Autowired
protected ApplicationEventPublisher publisher;
@@ -220,6 +222,22 @@ public SetDataEventOutcome setData(Task task, ObjectNode values) {
@Override
public SetDataEventOutcome setData(Task task, ObjectNode values, Map params) {
+ return setData(task, values, params, false);
+ }
+
+ /**
+ * Updates the data field's attributes of the provided task.
+ *
+ * @param task the task object of which the data are updated
+ * @param values information about how to update the data fields
+ * @param params additional information to be injected to the action delegate context
+ * @param runStrict if set to true, additional validations are going to be applied when updating the data fields. If
+ * set to false, minimal restrictions are considered.
+ *
+ * @return outcome containing Case, Task and changes that have been made.
+ * */
+ @Override
+ public SetDataEventOutcome setData(Task task, ObjectNode values, Map params, boolean runStrict) {
Case useCase = workflowService.findOne(task.getCaseId());
AbstractUser user = userService.getLoggedOrSystem();
@@ -232,70 +250,84 @@ public SetDataEventOutcome setData(Task task, ObjectNode values, Map {
String fieldId = entry.getKey();
DataField dataField = useCase.getDataSet().get(fieldId);
- if (dataField != null) {
- Field field = useCase.getPetriNet().getField(fieldId).get();
- outcome.addOutcomes(resolveDataEvents(field, DataEventType.SET, EventPhase.PRE, useCase, task, params));
- if (outcome.getMessage() == null) {
- Map dataSet = useCase.getPetriNet().getTransition(task.getTransitionId()).getDataSet();
- if (field.getEvents().containsKey(DataEventType.SET) &&
- ((DataEvent) field.getEvents().get(DataEventType.SET)).getMessage() != null) {
- outcome.setMessage(((DataEvent) field.getEvents().get(DataEventType.SET)).getMessage());
- } else if (dataSet.containsKey(fieldId)
- && dataSet.get(fieldId).getEvents().containsKey(DataEventType.SET)
- && dataSet.get(fieldId).getEvents().get(DataEventType.SET).getMessage() != null) {
- outcome.setMessage(dataSet.get(fieldId).getEvents().get(DataEventType.SET).getMessage());
- }
- }
- boolean modified = false;
- ChangedField changedField = new ChangedField();
- changedField.setId(fieldId);
- Object newValue = parseFieldsValues(entry.getValue(), dataField, task.getStringId());
- if (entry.getValue().has("value") || getFieldTypeFromNode((ObjectNode) entry.getValue()).equals("button")) {
- dataField.setValue(newValue);
- changedField.addAttribute("value", newValue);
- modified = true;
- }
- List allowedNets = parseAllowedNetsValue(entry.getValue());
- if (allowedNets != null) {
- dataField.setAllowedNets(allowedNets);
- changedField.addAttribute("allowedNets", allowedNets);
- modified = true;
- }
- String fieldType = getFieldTypeFromNode((ObjectNode) entry.getValue());
- Map filterMetadata = parseFilterMetadataValue((ObjectNode) entry.getValue(), fieldType);
- if (filterMetadata != null) {
- dataField.setFilterMetadata(filterMetadata);
- changedField.addAttribute("filterMetadata", filterMetadata);
- modified = true;
- }
- Map options = parseOptionsNode(entry.getValue(), fieldType);
- if (options != null) {
- setDataFieldOptions(options, dataField, changedField, fieldType);
- modified = true;
- }
- Set choices = parseChoicesNode((ObjectNode) entry.getValue(), fieldType);
- if (choices != null) {
- dataField.setChoices(choices);
- changedField.addAttribute("choices", choices.stream().map(i18nString -> i18nString.getTranslation(LocaleContextHolder.getLocale())).collect(Collectors.toSet()));
- modified = true;
+ if (dataField == null) {
+ return;
+ }
+ if (runStrict) {
+ if (!isDataFieldEditable(dataField, task.getTransitionId())) {
+ throw new IllegalArgumentException("Cannot edit data field [" + fieldId + "], which is not editable on transition [" + task.getTransitionId() + "].");
}
- Map properties = parseProperties(entry.getValue());
- if (properties != null) {
- outcome.addOutcome(this.changeComponentProperties(useCase, task, field.getStringId(), properties));
- modified = true;
+ Field> field = useCase.getField(fieldId);
+ if (field == null) {
+ throw new IllegalArgumentException("Such field with id [" + fieldId + "] does not exist in petri net [" + useCase.getPetriNetId() + "]");
}
- if (modified) {
- dataField.setLastModified(LocalDateTime.now());
+ if (setDataForbiddenFieldTypes.contains(field.getType())) {
+ return;
}
- if (dataConfigurationProperties.getValidation().isSetDataEnabled()) {
- validation.valid(useCase.getPetriNet().getDataSet().get(entry.getKey()), dataField);
+ }
+
+ Field field = useCase.getPetriNet().getField(fieldId).get();
+ outcome.addOutcomes(resolveDataEvents(field, DataEventType.SET, EventPhase.PRE, useCase, task, params));
+ if (outcome.getMessage() == null) {
+ Map dataSet = useCase.getPetriNet().getTransition(task.getTransitionId()).getDataSet();
+ if (field.getEvents().containsKey(DataEventType.SET) &&
+ ((DataEvent) field.getEvents().get(DataEventType.SET)).getMessage() != null) {
+ outcome.setMessage(((DataEvent) field.getEvents().get(DataEventType.SET)).getMessage());
+ } else if (dataSet.containsKey(fieldId)
+ && dataSet.get(fieldId).getEvents().containsKey(DataEventType.SET)
+ && dataSet.get(fieldId).getEvents().get(DataEventType.SET).getMessage() != null) {
+ outcome.setMessage(dataSet.get(fieldId).getEvents().get(DataEventType.SET).getMessage());
}
- outcome.addChangedField(fieldId, changedField);
- workflowService.save(useCase);
- publisher.publishEvent(new SetDataEvent(outcome, EventPhase.PRE, user));
- outcome.addOutcomes(resolveDataEvents(field, DataEventType.SET, EventPhase.POST, useCase, task, params));
- applyFieldConnectedChanges(useCase, field);
}
+ boolean modified = false;
+ ChangedField changedField = new ChangedField();
+ changedField.setId(fieldId);
+ Object newValue = parseFieldsValues(entry.getValue(), dataField, task.getStringId());
+ if (entry.getValue().has("value") || getFieldTypeFromNode((ObjectNode) entry.getValue()).equals("button")) {
+ dataField.setValue(newValue);
+ changedField.addAttribute("value", newValue);
+ modified = true;
+ }
+ List allowedNets = parseAllowedNetsValue(entry.getValue());
+ if (allowedNets != null) {
+ dataField.setAllowedNets(allowedNets);
+ changedField.addAttribute("allowedNets", allowedNets);
+ modified = true;
+ }
+ String fieldType = getFieldTypeFromNode((ObjectNode) entry.getValue());
+ Map filterMetadata = parseFilterMetadataValue((ObjectNode) entry.getValue(), fieldType);
+ if (filterMetadata != null) {
+ dataField.setFilterMetadata(filterMetadata);
+ changedField.addAttribute("filterMetadata", filterMetadata);
+ modified = true;
+ }
+ Map options = parseOptionsNode(entry.getValue(), fieldType);
+ if (options != null) {
+ setDataFieldOptions(options, dataField, changedField, fieldType);
+ modified = true;
+ }
+ Set choices = parseChoicesNode((ObjectNode) entry.getValue(), fieldType);
+ if (choices != null) {
+ dataField.setChoices(choices);
+ changedField.addAttribute("choices", choices.stream().map(i18nString -> i18nString.getTranslation(LocaleContextHolder.getLocale())).collect(Collectors.toSet()));
+ modified = true;
+ }
+ Map properties = parseProperties(entry.getValue());
+ if (properties != null) {
+ outcome.addOutcome(this.changeComponentProperties(useCase, task, field.getStringId(), properties));
+ modified = true;
+ }
+ if (modified) {
+ dataField.setLastModified(LocalDateTime.now());
+ }
+ if (dataConfigurationProperties.getValidation().isSetDataEnabled()) {
+ validation.valid(useCase.getPetriNet().getDataSet().get(entry.getKey()), dataField);
+ }
+ outcome.addChangedField(fieldId, changedField);
+ workflowService.save(useCase);
+ publisher.publishEvent(new SetDataEvent(outcome, EventPhase.PRE, user));
+ outcome.addOutcomes(resolveDataEvents(field, DataEventType.SET, EventPhase.POST, useCase, task, params));
+ applyFieldConnectedChanges(useCase, field);
});
updateDataset(useCase);
outcome.setCase(workflowService.save(useCase));
@@ -303,6 +335,15 @@ public SetDataEventOutcome setData(Task task, ObjectNode values, Map> behaviorMap = dataField.getBehavior();
+ if (behaviorMap == null) {
+ return false;
+ }
+ Set behaviorSet = behaviorMap.get(transId);
+ return behaviorSet != null && behaviorSet.contains(FieldBehavior.EDITABLE);
+ }
+
@Override
public GetDataGroupsEventOutcome getDataGroups(String taskId, Locale locale) {
return getDataGroups(taskId, locale, new HashSet<>(), 0, null);
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/TaskService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/TaskService.java
index ac21c61ae5..cc81367878 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/TaskService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/TaskService.java
@@ -976,6 +976,9 @@ public SetDataEventOutcome getMainOutcome(Map outco
}
}
mainOutcome = outcomes.remove(key);
+ if (mainOutcome == null) {
+ return null;
+ }
mainOutcome.addOutcomes(new ArrayList<>(outcomes.values()));
return mainOutcome;
}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IDataService.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IDataService.java
index 4426b3500a..7f1f5038a6 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IDataService.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IDataService.java
@@ -41,6 +41,8 @@ public interface IDataService {
SetDataEventOutcome setData(Task task, ObjectNode values, Map params);
+ SetDataEventOutcome setData(Task task, ObjectNode values, Map params, boolean runStrict);
+
FileFieldInputStream getFile(Case useCase, Task task, FileField field, boolean forPreview) throws FileNotFoundException;
FileFieldInputStream getFile(Case useCase, Task task, FileField field, boolean forPreview, Map params) throws FileNotFoundException;
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/web/AbstractTaskController.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/web/AbstractTaskController.java
index eafa862bf8..bbde665db3 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/web/AbstractTaskController.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/web/AbstractTaskController.java
@@ -7,6 +7,8 @@
import com.netgrif.application.engine.elastic.service.interfaces.IElasticTaskService;
import com.netgrif.application.engine.elastic.web.requestbodies.singleaslist.SingleElasticTaskSearchRequestAsList;
import com.netgrif.application.engine.eventoutcomes.LocalisedEventOutcomeFactory;
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.FieldType;
+import com.netgrif.application.engine.objects.petrinet.domain.dataset.localised.LocalisedField;
import com.netgrif.application.engine.workflow.web.responsebodies.LocalisedTaskResource;
import com.netgrif.application.engine.objects.petrinet.domain.throwable.TransitionNotExecutableException;
import com.netgrif.application.engine.workflow.domain.IllegalArgumentWithChangedFieldsException;
@@ -19,6 +21,7 @@
import com.netgrif.application.engine.workflow.service.FileFieldInputStream;
import com.netgrif.application.engine.workflow.service.interfaces.IDataService;
import com.netgrif.application.engine.workflow.service.interfaces.ITaskService;
+import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService;
import com.netgrif.application.engine.workflow.web.requestbodies.file.FileFieldRequest;
import com.netgrif.application.engine.workflow.web.requestbodies.singleaslist.SingleTaskSearchRequestAsList;
import com.netgrif.application.engine.workflow.web.responsebodies.*;
@@ -41,10 +44,8 @@
import org.springframework.web.multipart.MultipartFile;
import java.io.FileNotFoundException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
+import java.util.*;
+import java.util.stream.Collectors;
public abstract class AbstractTaskController {
@@ -54,6 +55,8 @@ public abstract class AbstractTaskController {
private final IDataService dataService;
+ private final IWorkflowService workflowService;
+
private final IElasticTaskService searchService;
private final UserService userService;
@@ -61,10 +64,12 @@ public abstract class AbstractTaskController {
public AbstractTaskController(ITaskService taskService,
IDataService dataService,
IElasticTaskService searchService,
+ IWorkflowService workflowService,
UserService userService) {
this.taskService = taskService;
this.dataService = dataService;
this.searchService = searchService;
+ this.workflowService = workflowService;
this.userService = userService;
}
@@ -216,9 +221,32 @@ public EntityModel getData(String taskId, Locale locale
public EntityModel setData(String taskId, ObjectNode dataBody, Locale locale) {
try {
+ List dataGroups = dataService.getDataGroups(taskId, locale).getData();
+ Set referencedTaskIds = new HashSet<>();
+ referencedTaskIds.add(taskId);
+ for (com.netgrif.application.engine.objects.petrinet.domain.DataGroup dataGroup : dataGroups) {
+ Set referencedTaskIdsByDataGroup = dataGroup.getFields().getContent().stream()
+ .filter(someField -> someField instanceof LocalisedField localisedField
+ && localisedField.getType() == FieldType.TASK_REF
+ && localisedField.getValue() instanceof List
+ && !((List>) localisedField.getValue()).isEmpty())
+ .map(localisedField -> (List) ((LocalisedField) localisedField).getValue())
+ .flatMap(List::stream)
+ .collect(Collectors.toSet());
+ referencedTaskIds.addAll(referencedTaskIdsByDataGroup);
+ }
Map outcomes = new HashMap<>();
- dataBody.fields().forEachRemaining(it -> outcomes.put(it.getKey(), dataService.setData(it.getKey(), it.getValue().deepCopy())));
+ dataBody.fields().forEachRemaining(fieldChangesEntry -> {
+ String taskIdToChangeWith = fieldChangesEntry.getKey();
+ if (!referencedTaskIds.contains(taskIdToChangeWith)) {
+ return;
+ }
+ Task taskToChangeWith = taskService.findOne(taskIdToChangeWith);
+ outcomes.put(taskIdToChangeWith, dataService.setData(taskToChangeWith,
+ fieldChangesEntry.getValue().deepCopy(), new HashMap<>(), true));
+ });
SetDataEventOutcome mainOutcome = taskService.getMainOutcome(outcomes, taskId);
+ mainOutcome = handleMainSetDataEventOutcome(mainOutcome, taskId);
return EventOutcomeWithMessageResource.successMessage("Data field values have been successfully set",
LocalisedEventOutcomeFactory.from(mainOutcome, LocaleContextHolder.getLocale()));
} catch (IllegalArgumentWithChangedFieldsException e) {
@@ -236,6 +264,7 @@ public EntityModel saveFile(String taskId, MultipartFil
Map outcomes = new HashMap<>();
outcomes.put(dataBody.getParentTaskId(), dataService.saveFile(dataBody.getParentTaskId(), dataBody.getFieldId(), multipartFile));
SetDataEventOutcome mainOutcome = taskService.getMainOutcome(outcomes, taskId);
+ mainOutcome = handleMainSetDataEventOutcome(mainOutcome, taskId);
return EventOutcomeWithMessageResource.successMessage("Data field values have been successfully set",
LocalisedEventOutcomeFactory.from(mainOutcome, LocaleContextHolder.getLocale()));
} catch (IllegalArgumentWithChangedFieldsException e) {
@@ -268,7 +297,8 @@ public EntityModel deleteFile(String taskId, String fie
Map outcomes = new HashMap<>();
outcomes.put(taskId, dataService.deleteFile(taskId, fieldId));
SetDataEventOutcome mainOutcome = taskService.getMainOutcome(outcomes, taskId);
- return EventOutcomeWithMessageResource.successMessage("Data field values have been sucessfully set",
+ mainOutcome = handleMainSetDataEventOutcome(mainOutcome, taskId);
+ return EventOutcomeWithMessageResource.successMessage("Data field values have been successfully set",
LocalisedEventOutcomeFactory.from(mainOutcome, LocaleContextHolder.getLocale()));
}
@@ -276,7 +306,8 @@ public EntityModel saveFiles(String taskId, MultipartFi
Map outcomes = new HashMap<>();
outcomes.put(requestBody.getParentTaskId(), dataService.saveFiles(requestBody.getParentTaskId(), requestBody.getFieldId(), multipartFiles));
SetDataEventOutcome mainOutcome = taskService.getMainOutcome(outcomes, taskId);
- return EventOutcomeWithMessageResource.successMessage("Data field values have been sucessfully set",
+ mainOutcome = handleMainSetDataEventOutcome(mainOutcome, taskId);
+ return EventOutcomeWithMessageResource.successMessage("Data field values have been successfully set",
LocalisedEventOutcomeFactory.from(mainOutcome, LocaleContextHolder.getLocale()));
}
@@ -300,7 +331,8 @@ public EntityModel deleteNamedFile(String taskId, Strin
Map outcomes = new HashMap<>();
outcomes.put(taskId, dataService.deleteFileByName(taskId, fieldId, name));
SetDataEventOutcome mainOutcome = taskService.getMainOutcome(outcomes, taskId);
- return EventOutcomeWithMessageResource.successMessage("Data field values have been sucessfully set",
+ mainOutcome = handleMainSetDataEventOutcome(mainOutcome, taskId);
+ return EventOutcomeWithMessageResource.successMessage("Data field values have been successfully set",
LocalisedEventOutcomeFactory.from(mainOutcome, LocaleContextHolder.getLocale()));
}
@@ -316,4 +348,13 @@ public ResponseEntity getFilePreview(String taskId, String fieldId) th
.headers(headers)
.body(fileFieldInputStream != null ? new InputStreamResource(fileFieldInputStream.getInputStream()) : null);
}
+
+ protected SetDataEventOutcome handleMainSetDataEventOutcome(SetDataEventOutcome mainOutcome, String taskId) {
+ if (mainOutcome != null) {
+ return mainOutcome;
+ }
+
+ Task task = taskService.findOne(taskId);
+ return new SetDataEventOutcome(workflowService.findOne(task.getCaseId()), task);
+ }
}
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/web/PublicTaskController.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/web/PublicTaskController.java
index e6623f3dd9..932db377fe 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/web/PublicTaskController.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/web/PublicTaskController.java
@@ -9,6 +9,7 @@
import com.netgrif.application.engine.workflow.domain.eventoutcomes.response.EventOutcomeWithMessage;
import com.netgrif.application.engine.workflow.service.interfaces.IDataService;
import com.netgrif.application.engine.workflow.service.interfaces.ITaskService;
+import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService;
import com.netgrif.application.engine.workflow.web.requestbodies.file.FileFieldRequest;
import com.netgrif.application.engine.workflow.web.requestbodies.singleaslist.SingleTaskSearchRequestAsList;
import com.netgrif.application.engine.workflow.web.responsebodies.LocalisedTaskResource;
@@ -54,8 +55,9 @@ public class PublicTaskController extends AbstractTaskController {
public PublicTaskController(ITaskService taskService,
IDataService dataService,
+ IWorkflowService workflowService,
UserService userService) {
- super(taskService, dataService, null, userService);
+ super(taskService, dataService, null, workflowService, userService);
this.taskService = taskService;
this.dataService = dataService;
this.userService = userService;
diff --git a/application-engine/src/main/java/com/netgrif/application/engine/workflow/web/TaskController.java b/application-engine/src/main/java/com/netgrif/application/engine/workflow/web/TaskController.java
index bab31f35cf..2de3c52fed 100644
--- a/application-engine/src/main/java/com/netgrif/application/engine/workflow/web/TaskController.java
+++ b/application-engine/src/main/java/com/netgrif/application/engine/workflow/web/TaskController.java
@@ -9,6 +9,7 @@
import com.netgrif.application.engine.workflow.domain.eventoutcomes.response.EventOutcomeWithMessage;
import com.netgrif.application.engine.workflow.service.interfaces.IDataService;
import com.netgrif.application.engine.workflow.service.interfaces.ITaskService;
+import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService;
import com.netgrif.application.engine.workflow.web.requestbodies.file.FileFieldRequest;
import com.netgrif.application.engine.workflow.web.requestbodies.singleaslist.SingleTaskSearchRequestAsList;
import com.netgrif.application.engine.workflow.web.responsebodies.CountResponse;
@@ -55,8 +56,9 @@ public class TaskController extends AbstractTaskController {
public TaskController(ITaskService taskService,
IDataService dataService,
IElasticTaskService searchService,
+ IWorkflowService workflowService,
UserService userService) {
- super(taskService, dataService, searchService, userService);
+ super(taskService, dataService, searchService, workflowService, userService);
}
@Override
diff --git a/application-engine/src/test/groovy/com/netgrif/application/engine/workflow/TaskControllerTest.groovy b/application-engine/src/test/groovy/com/netgrif/application/engine/workflow/TaskControllerTest.groovy
index 569de8e894..8fd652ee55 100644
--- a/application-engine/src/test/groovy/com/netgrif/application/engine/workflow/TaskControllerTest.groovy
+++ b/application-engine/src/test/groovy/com/netgrif/application/engine/workflow/TaskControllerTest.groovy
@@ -1,23 +1,27 @@
package com.netgrif.application.engine.workflow
-import com.netgrif.application.engine.objects.auth.domain.ActorTransformer
-import com.netgrif.application.engine.objects.auth.domain.User
-import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService
-import com.netgrif.application.engine.adapter.spring.petrinet.service.ProcessRoleService
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.fasterxml.jackson.databind.node.ObjectNode
import com.netgrif.application.engine.TestHelper
-import com.netgrif.application.engine.objects.auth.domain.Authority
-import com.netgrif.application.engine.objects.auth.domain.enums.UserState
import com.netgrif.application.engine.auth.service.AuthorityService
import com.netgrif.application.engine.auth.service.UserService
import com.netgrif.application.engine.elastic.service.interfaces.IElasticTaskService
+import com.netgrif.application.engine.objects.auth.domain.ActorTransformer
+import com.netgrif.application.engine.objects.auth.domain.Authority
+import com.netgrif.application.engine.objects.auth.domain.User
+import com.netgrif.application.engine.objects.auth.domain.enums.UserState
import com.netgrif.application.engine.objects.petrinet.domain.PetriNet
import com.netgrif.application.engine.objects.petrinet.domain.VersionType
import com.netgrif.application.engine.objects.petrinet.domain.dataset.FileListFieldValue
+import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole
+import com.netgrif.application.engine.objects.workflow.domain.Case
+import com.netgrif.application.engine.objects.workflow.domain.DataField
+import com.netgrif.application.engine.objects.workflow.domain.Task
+import com.netgrif.application.engine.petrinet.service.ProcessRoleService
+import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService
import com.netgrif.application.engine.startup.ImportHelper
import com.netgrif.application.engine.startup.runner.SuperCreatorRunner
import com.netgrif.application.engine.utils.FullPageRequest
-import com.netgrif.application.engine.objects.workflow.domain.Case
-import com.netgrif.application.engine.objects.workflow.domain.Task
import com.netgrif.application.engine.workflow.service.TaskSearchService
import com.netgrif.application.engine.workflow.service.TaskService
import com.netgrif.application.engine.workflow.service.interfaces.IDataService
@@ -25,7 +29,6 @@ import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowServi
import com.netgrif.application.engine.workflow.web.TaskController
import com.netgrif.application.engine.workflow.web.WorkflowController
import com.netgrif.application.engine.workflow.web.requestbodies.TaskSearchRequest
-import com.netgrif.application.engine.objects.petrinet.domain.roles.ProcessRole
import com.netgrif.application.engine.workflow.web.responsebodies.TaskReference
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
@@ -86,7 +89,9 @@ class TaskControllerTest {
@Autowired
private TaskController taskController
- private PetriNet net
+ private PetriNet allDataNet
+
+ private PetriNet setDataNet
private Case useCase
@@ -106,7 +111,7 @@ class TaskControllerTest {
state: UserState.ACTIVE,
authoritySet: [authorityService.getOrCreate(Authority.user)] as Set,
processRoles: [] as Set), null)
- importNet()
+ importNets()
}
@Test
@@ -118,7 +123,7 @@ class TaskControllerTest {
@Test
void testDeleteFile() {
- Case testCase = helper.createCase("My case", net)
+ Case testCase = helper.createCase("My case", allDataNet)
String taskId = testCase.tasks.find {it.transition == "1"}.task
dataService.saveFile(taskId, "file", new MockMultipartFile("test", new byte[] {}))
@@ -132,7 +137,7 @@ class TaskControllerTest {
@Test
void testDeleteFileByName() {
- Case testCase = helper.createCase("My case", net)
+ Case testCase = helper.createCase("My case", allDataNet)
String taskId = testCase.tasks.find {it.transition == "1"}.task
dataService.saveFiles(taskId, "fileList", new MockMultipartFile[] {new MockMultipartFile("test", "test", null, new byte[] {})})
@@ -144,6 +149,79 @@ class TaskControllerTest {
assert ((FileListFieldValue) testCase.dataSet["fileList"].value).namesPaths == null || ((FileListFieldValue) testCase.dataSet["fileList"].value).namesPaths.size() == 0
}
+ @Test
+ void testSetDataFieldTypeRestriction() {
+ Case testCase = helper.createCase("My case", setDataNet)
+ String taskId = testCase.tasks.find { it.transition == "testSetDataFieldTypeRestriction" }.task
+
+ ObjectNode dataSet = populateNestedDataset([(taskId):["taskRef_0": ["type": "taskRef", "value": [taskId]]]])
+ def response = taskController.setData(taskId, dataSet, Locale.default)
+ assert response != null && response.content.outcome != null
+ assert response.content.outcome.changedFields.changedFields.isEmpty()
+ assert ((List) workflowService.findOne(testCase.stringId).getDataField("taskRef_0").getValue()).isEmpty()
+
+ dataSet = populateNestedDataset([(taskId):["caseRef_0": ["type": "caseRef", "value": [testCase.stringId]]]])
+ response = taskController.setData(taskId, dataSet, Locale.default)
+ assert response != null && response.content.outcome != null
+ assert response.content.outcome.changedFields.changedFields.isEmpty()
+ assert ((List) workflowService.findOne(testCase.stringId).getDataField("caseRef_0").getValue()).isEmpty()
+ }
+
+ @Test
+ void testSetDataVisibleField() {
+ Case testCase = helper.createCase("My case", setDataNet)
+ String taskId = testCase.tasks.find { it.transition == "data" }.task
+
+ ObjectNode dataSet = populateNestedDataset([(taskId):["text_1": ["type": "text", "value": "awd"]]])
+ def response = taskController.setData(taskId, dataSet, Locale.default)
+ assert response != null && response.content.outcome == null
+ assert response.content.error != null
+
+ // todo: test visible behavior based on parent taskRef behavior
+ }
+
+ @Test
+ void testSetDataNestedTaskRefRestrictions() {
+ Case testCase1 = helper.createCase("testCase1", setDataNet)
+ String taskId = testCase1.tasks.find { it.transition == "testSetDataNestedTaskRefRestrictions" }.task
+ Case testCase2 = helper.createCase("testCase2", setDataNet)
+ Case testCase3 = helper.createCase("testCase3", setDataNet)
+
+ DataField case1DataField = testCase1.getDataField("taskRef_0")
+ case1DataField.setValue(List.of(testCase2.tasks.find { it.transition == "testSetDataNestedTaskRefRestrictions" }.task))
+ workflowService.save(testCase1)
+
+ DataField case2DataField = testCase2.getDataField("taskRef_0")
+ case2DataField.setValue(List.of(testCase3.tasks.find { it.transition == "data" }.task))
+ workflowService.save(testCase2)
+
+ String nestedOtherTaskId = testCase2.tasks.find { it.transition == "data" }.task
+ ObjectNode dataSet = populateNestedDataset([(nestedOtherTaskId):["text_0": ["type": "text", "value": "awd"]]])
+ def response = taskController.setData(taskId, dataSet, Locale.default)
+ assert response != null && response.content.outcome != null
+ assert response.content.outcome.changedFields.changedFields.isEmpty()
+ assert workflowService.findOne(testCase2.stringId).getDataField("text_0").getValue() == null
+
+ String nestedTaskId = testCase3.tasks.find { it.transition == "data" }.task
+ dataSet = populateNestedDataset([(nestedTaskId):["text_0": ["type": "text", "value": "awd"]]])
+ response = taskController.setData(taskId, dataSet, Locale.default)
+ assert response != null && response.content.outcome != null
+ assert !response.content.outcome.changedFields.changedFields.isEmpty()
+ assert workflowService.findOne(testCase3.stringId).getDataField("text_0").getValue() == "awd"
+ }
+
+ @Test
+ void testSetDataNonReferencedField() {
+ Case testCase = helper.createCase("My case", setDataNet)
+ String taskId = testCase.tasks.find { it.transition == "testSetDataNonReferencedField" }.task
+
+ ObjectNode dataSet = populateNestedDataset([(taskId):["text_1": ["type": "text", "value": "awd"]]])
+ def response = taskController.setData(taskId, dataSet, Locale.default)
+
+ assert response != null && response.content.outcome == null
+ assert response.content.error != null
+ }
+
void testWithRoleAndUserref() {
createCase()
@@ -167,15 +245,19 @@ class TaskControllerTest {
assert !findTasksByMongo().empty
}
- void importNet() {
- PetriNet netOptional = helper.createNet("all_data_refs.xml", VersionType.MAJOR).get()
- assert netOptional != null
- net = netOptional
+ void importNets() {
+ PetriNet allDataNet = helper.createNet("all_data_refs.xml", VersionType.MAJOR).get()
+ assert allDataNet != null
+ this.allDataNet = allDataNet
+
+ PetriNet setDataNet = helper.createNet("task_controller_set_data.xml", VersionType.MAJOR).get()
+ assert setDataNet != null
+ this.setDataNet = setDataNet
}
void createCase() {
useCase = null
- useCase = helper.createCase("My case", net)
+ useCase = helper.createCase("My case", allDataNet)
assert useCase != null
}
@@ -203,7 +285,7 @@ class TaskControllerTest {
}
void setUserRole() {
- List roles = processRoleService.findAllByNetStringId(net.stringId)
+ List roles = processRoleService.findAllByNetStringId(allDataNet.stringId)
for (ProcessRole role : roles) {
if (role.importId == "process_role") {
@@ -219,4 +301,10 @@ class TaskControllerTest {
Page tasks = taskService.search(taskSearchRequestList, new FullPageRequest(), ActorTransformer.toLoggedUser(userService.findUserByUsername(DUMMY_USER_MAIL, null).get()), Locale.ENGLISH, false)
return tasks
}
+
+ static ObjectNode populateNestedDataset(Map>> data) {
+ ObjectMapper mapper = new ObjectMapper()
+ String json = mapper.writeValueAsString(data)
+ return mapper.readTree(json) as ObjectNode
+ }
}
diff --git a/application-engine/src/test/resources/petriNets/task_controller_set_data.xml b/application-engine/src/test/resources/petriNets/task_controller_set_data.xml
new file mode 100644
index 0000000000..60743a813a
--- /dev/null
+++ b/application-engine/src/test/resources/petriNets/task_controller_set_data.xml
@@ -0,0 +1,154 @@
+
+ task_controller_set_data
+ 1.0.0
+ TCS
+ task_controller_set_data
+ device_hub
+ true
+ true
+ false
+
+ taskRef_0
+
+
+
+ caseRef_0
+
+
+
+ text_0
+
+
+
+ text_1
+
+
+
+ testSetDataFieldTypeRestriction
+ 720
+ 336
+
+
+ testSetDataFieldTypeRestriction_0
+ 4
+ grid
+
+ taskRef_0
+
+ editable
+
+
+ 1
+ 1
+ 1
+ 2
+ material
+ outline
+
+
+
+ caseRef_0
+
+ editable
+
+
+ 1
+ 2
+ 1
+ 2
+ material
+ outline
+
+
+
+
+
+ testSetDataNestedTaskRefRestrictions
+ 720
+ 436
+
+
+ testSetDataNestedTaskRefRestrictions_0
+ 4
+ grid
+
+ taskRef_0
+
+ editable
+
+
+ 1
+ 1
+ 1
+ 2
+ material
+ outline
+
+
+
+
+
+ data
+ 720
+ 564
+
+
+ data_0
+ 4
+ grid
+
+ text_0
+
+ editable
+
+
+ 1
+ 1
+ 1
+ 2
+ material
+ outline
+
+
+
+ text_1
+
+ visible
+
+
+ 1
+ 2
+ 1
+ 2
+ material
+ outline
+
+
+
+
+
+ testSetDataNonReferencedField
+ 720
+ 664
+
+
+ data_0
+ 4
+ grid
+
+ text_0
+
+ editable
+
+
+ 1
+ 1
+ 1
+ 2
+ material
+ outline
+
+
+
+
+
\ No newline at end of file