Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions flow-engine-example/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>com.codingapi.flow</groupId>
<artifactId>flow-engine-parent</artifactId>
<version>0.0.58</version>
<version>0.0.61</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down Expand Up @@ -73,4 +73,4 @@
</plugin>
</plugins>
</build>
</project>
</project>
4 changes: 2 additions & 2 deletions flow-engine-framework/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>com.codingapi.flow</groupId>
<artifactId>flow-engine-parent</artifactId>
<version>0.0.58</version>
<version>0.0.61</version>
</parent>

<name>flow-engine-framework</name>
Expand Down Expand Up @@ -34,4 +34,4 @@

</dependencies>

</project>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public FlowDelayTriggerService createDelayTriggerService(DelayTask task) {
*/
public FlowActionService createFlowActionService(FlowSession flowSession) {
this.verify();
return new FlowActionService(flowSession.toActionRequest(),this);
return new FlowActionService(flowSession.toActionRequest(), this, true);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public List<IFlowAction> filterActions(FlowSession flowSession) {
List<IFlowAction> actions = new ArrayList<>();
if (this.actions != null) {
for (IFlowAction action : this.actions) {
if (action.show(flowSession)) {
if (action.enable() && action.show(flowSession)) {
actions.add(action);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public FlowDelayTriggerService createDelayTriggerService(DelayTask task) {

@Override
public FlowActionService createFlowActionService(FlowSession flowSession) {
return new FlowActionService(flowSession.toActionRequest(), this);
return new FlowActionService(flowSession.toActionRequest(), this, true);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ public class WorkflowService {
public void saveWorkflowVersion(WorkflowVersion currentVersion, boolean creatable, boolean enable) {
List<WorkflowVersion> updateList = new ArrayList<>();

Workflow workflow = currentVersion.toWorkflow();
workflow.filterPermissions();

currentVersion.enableVersion();
if (currentVersion.getId() == 0) {
// 新创建的版本,替换脚本
Expand All @@ -61,9 +64,6 @@ public void saveWorkflowVersion(WorkflowVersion currentVersion, boolean creatabl
}

workflowVersionRepository.saveAll(updateList);
Workflow workflow = currentVersion.toWorkflow();
workflow.filterPermissions();

if (enable) {
try {
workflow.enable();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,19 @@ public class FlowActionService {

private final IRepositoryHolder repositoryHolder;

private final boolean allowDisabledAction;

public FlowActionService(FlowActionRequest request,IRepositoryHolder repositoryHolder) {
this(request, repositoryHolder, false);
}

public FlowActionService(FlowActionRequest request, IRepositoryHolder repositoryHolder, boolean allowDisabledAction) {
this.request = request;
this.flowOperatorGateway = repositoryHolder.getFlowOperatorGateway();
this.flowRecordService = repositoryHolder.getFlowRecordService();
this.workflowService = repositoryHolder.getWorkflowService();
this.repositoryHolder = repositoryHolder;
this.allowDisabledAction = allowDisabledAction;
}

public ActionResponse action() {
Expand Down Expand Up @@ -75,7 +82,7 @@ public ActionResponse action() {
throw FlowNotFoundException.node(flowRecord.getNodeId());
}
IFlowAction flowAction = currentNode.actionManager().getActionById(request.getAdvice().getActionId());
if (flowAction == null || !flowAction.enable()) {
if (flowAction == null || (!flowAction.enable() && !allowDisabledAction)) {
throw FlowNotFoundException.action(request.getAdvice().getActionId());
}

Expand All @@ -100,4 +107,3 @@ public ActionResponse action() {
return ActionResponseContext.getInstance().get();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.codingapi.flow.manager;

import com.codingapi.flow.action.ActionDisplay;
import com.codingapi.flow.action.IFlowAction;
import com.codingapi.flow.record.FlowRecord;
import com.codingapi.flow.session.FlowSession;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;

class ActionManagerTest {

@Test
void should_only_return_enabled_actions_that_are_allowed_to_display() {
IFlowAction enabledAction = new TestAction("enabled", true, true);
IFlowAction disabledAction = new TestAction("disabled", false, true);
IFlowAction hiddenAction = new TestAction("hidden", true, false);

ActionManager actionManager = new ActionManager(List.of(enabledAction, disabledAction, hiddenAction));

List<IFlowAction> actions = actionManager.filterActions(null);

assertEquals(List.of(enabledAction), actions);
}

private record TestAction(String id, boolean enable, boolean displayable) implements IFlowAction {

@Override
public String type() {
return "TEST";
}

@Override
public String title() {
return id;
}

@Override
public ActionDisplay display() {
return null;
}

@Override
public boolean show(FlowSession flowSession) {
return displayable;
}

@Override
public List<FlowRecord> generateRecords(FlowSession flowSession) {
return List.of();
}

@Override
public void run(FlowSession flowSession) {
}

@Override
public Map<String, Object> toMap() {
return Map.of();
}

@Override
public void copy(IFlowAction source) {
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.codingapi.flow.action.IFlowAction;
import com.codingapi.flow.action.actions.CustomAction;
import com.codingapi.flow.action.actions.PassAction;
import com.codingapi.flow.builder.ActionBuilder;
import com.codingapi.flow.builder.FormFieldPermissionsBuilder;
import com.codingapi.flow.builder.NodeStrategyBuilder;
Expand Down Expand Up @@ -37,6 +38,8 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class FlowDetailServiceTest {

Expand Down Expand Up @@ -386,4 +389,68 @@ void processNodes_shouldShowNextApprovalNodeOperator() {
assertEquals(c.getUserId(), nextApprovalNode.getOperators().get(0).getFlowOperator().getUserId());
assertEquals(c.getName(), nextApprovalNode.getOperators().get(0).getFlowOperator().getName());
}

@Test
void customPassAction_shouldExecuteWhenDefaultPassActionIsDisabled() {
User a = new User(1, "a");
User b = new User(2, "b");
factory.userGateway.save(a);
factory.userGateway.save(b);
GatewayContext.getInstance().setFlowOperatorGateway(factory.userGateway);

FlowForm form = FlowFormBuilder.builder()
.name("审批流程")
.code("custom-pass")
.addField("标题", "title", DataType.STRING)
.build();

StartNode startNode = StartNode.builder().build();
ApprovalNode bNode = ApprovalNode.builder()
.name("B审批")
.strategies(NodeStrategyBuilder.builder()
.addStrategy(new OperatorLoadStrategy(
FlowGroovyScriptFactory.createOperatorLoadScript("def run(request){return [2]}").getKey()))
.build())
.build();

IFlowAction defaultPassAction = bNode.actionManager().getActionByType("PASS");
((PassAction) defaultPassAction).setEnable(false);
CustomAction customPassAction = CustomAction.defaultAction();
bNode.actionManager().getActions().add(customPassAction);

Workflow workflow = WorkflowBuilder.builder()
.title("审批流程")
.code("custom-pass")
.createdOperator(a)
.form(form)
.addNode(startNode)
.addNode(bNode)
.addNode(EndNode.builder().build())
.build();
factory.workflowService.saveWorkflow(workflow);

Map<String, Object> data = Map.of("title", "test");
FlowCreateRequest createRequest = new FlowCreateRequest();
createRequest.setWorkCode(workflow.getCode());
createRequest.setFormData(data);
createRequest.setActionId(startNode.actionManager().getActionByType("PASS").id());
createRequest.setOperatorId(a.getUserId());
factory.flowService.create(createRequest);

FlowRecord startRecord = factory.flowRecordRepository.findTodoByOperator(a.getUserId()).get(0);
FlowActionRequest startRequest = new FlowActionRequest();
startRequest.setFormData(data);
startRequest.setRecordId(startRecord.getId());
startRequest.setAdvice(new FlowAdviceBody(startNode.actionManager().getActionByType("PASS").id(), "提交", a.getUserId()));
factory.flowService.action(startRequest);

FlowRecord bRecord = factory.flowRecordRepository.findTodoByOperator(b.getUserId()).get(0);
FlowActionRequest customPassRequest = new FlowActionRequest();
customPassRequest.setFormData(data);
customPassRequest.setRecordId(bRecord.getId());
customPassRequest.setAdvice(new FlowAdviceBody(customPassAction.id(), "通过", b.getUserId()));

assertDoesNotThrow(() -> factory.flowService.action(customPassRequest));
assertTrue(bRecord.isDone());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package com.codingapi.flow.service;

import com.codingapi.flow.form.DataType;
import com.codingapi.flow.form.FlowForm;
import com.codingapi.flow.form.FormField;
import com.codingapi.flow.form.permission.FormFieldPermission;
import com.codingapi.flow.form.permission.PermissionType;
import com.codingapi.flow.node.nodes.ApprovalNode;
import com.codingapi.flow.repository.WorkflowRepository;
import com.codingapi.flow.repository.WorkflowRuntimeRepository;
import com.codingapi.flow.repository.WorkflowVersionRepository;
import com.codingapi.flow.repository.WorkflowRepositoryImpl;
import com.codingapi.flow.repository.WorkflowRuntimeRepositoryImpl;
import com.codingapi.flow.strategy.node.FormFieldPermissionStrategy;
import com.codingapi.flow.workflow.Workflow;
import com.codingapi.flow.workflow.WorkflowBuilder;
import com.codingapi.flow.workflow.WorkflowVersion;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;

class WorkflowServiceTest {

@Test
void should_align_historical_field_permissions_before_saving_version() {
SnapshotWorkflowVersionRepository versionRepository = new SnapshotWorkflowVersionRepository();
WorkflowRepository workflowRepository = new WorkflowRepositoryImpl();
WorkflowRuntimeRepository runtimeRepository = new WorkflowRuntimeRepositoryImpl();
WorkflowService service = new WorkflowService(versionRepository, workflowRepository, runtimeRepository);

ApprovalNode approvalNode = ApprovalNode.defaultNode();
FormFieldPermission legacyPermission = new FormFieldPermission();
legacyPermission.setFormCode("leave");
legacyPermission.setFieldCode("desc");
legacyPermission.setType(PermissionType.READ);
approvalNode.strategyManager()
.getStrategy(FormFieldPermissionStrategy.class)
.setFieldPermissions(List.of(legacyPermission));

Workflow workflow = WorkflowBuilder.builder()
.id("workflow-1")
.code("leave-workflow")
.title("请假流程")
.form(formWithDescriptionField())
.addNode(approvalNode)
.build(false);

service.saveWorkflow(workflow);

FormFieldPermission permission = versionRepository.getSavedPermissions()
.get(0);
assertEquals("description", permission.getFieldCode());
assertEquals(PermissionType.WRITE, permission.getType());
}

private FlowForm formWithDescriptionField() {
FormField field = new FormField();
field.setCode("description");
field.setName("请假说明");
field.setType("input");
field.setDataType(DataType.STRING);

FlowForm form = new FlowForm();
form.setCode("leave");
form.setName("请假单");
form.setFields(List.of(field));
form.setSubForms(List.of());
return form;
}

private static class SnapshotWorkflowVersionRepository implements WorkflowVersionRepository {

private List<FormFieldPermission> savedPermissions = List.of();

private List<FormFieldPermission> getSavedPermissions() {
return savedPermissions;
}

@Override
public WorkflowVersion get(long id) {
return null;
}

@Override
public void delete(String workId) {
}

@Override
public List<WorkflowVersion> findVersion(String workId) {
return List.of();
}

@Override
public void saveAll(List<WorkflowVersion> versionList) {
versionList.forEach(this::save);
}

@Override
public void save(WorkflowVersion workflowVersion) {
savedPermissions = workflowVersion.toWorkflow()
.getNodes()
.get(0)
.strategyManager()
.getStrategy(FormFieldPermissionStrategy.class)
.getFieldPermissions()
.stream()
.map(this::copyPermission)
.toList();
}

@Override
public void delete(long id) {
}

private FormFieldPermission copyPermission(FormFieldPermission permission) {
FormFieldPermission copy = new FormFieldPermission();
copy.setFormCode(permission.getFormCode());
copy.setFieldCode(permission.getFieldCode());
copy.setType(permission.getType());
return copy;
}
}
}
Loading