diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/service/WorkflowService.java b/flow-engine-framework/src/main/java/com/codingapi/flow/service/WorkflowService.java index 3fd4737a..e406d2d4 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/service/WorkflowService.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/service/WorkflowService.java @@ -4,6 +4,7 @@ import com.codingapi.flow.repository.WorkflowRepository; import com.codingapi.flow.repository.WorkflowRuntimeRepository; import com.codingapi.flow.repository.WorkflowVersionRepository; +import com.codingapi.flow.utils.Base64Utils; import com.codingapi.flow.workflow.Workflow; import com.codingapi.flow.workflow.WorkflowVersion; import com.codingapi.flow.workflow.runtime.WorkflowRuntime; @@ -164,4 +165,17 @@ public void saveWorkflowRuntime(WorkflowRuntime workflowRuntime) { public WorkflowRuntime getWorkflowRuntime(String workId, long workVersion) { return this.workflowRuntimeRepository.getByWorkId(workId, workVersion); } + + /** + * 导入流程 + * @param body base64 + * @return 流程id + */ + public String importWorkflow(String body) { + String json = Base64Utils.toJson(body); + Workflow workflow = Workflow.formJson(json); + workflow.resetWorkflow(); + this.saveWorkflow(workflow); + return workflow.getId(); + } } diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/utils/Base64Utils.java b/flow-engine-framework/src/main/java/com/codingapi/flow/utils/Base64Utils.java new file mode 100644 index 00000000..73e460c9 --- /dev/null +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/utils/Base64Utils.java @@ -0,0 +1,30 @@ +package com.codingapi.flow.utils; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public class Base64Utils { + + public static String toJson(String base64) { + if (base64 == null) { + return null; + } + // 去掉前缀 + if (base64.contains(",")) { + base64 = base64.substring(base64.indexOf(",") + 1); + } + try { + byte[] decoded; + try { + decoded = Base64.getDecoder().decode(base64); + } catch (IllegalArgumentException e) { + decoded = Base64.getUrlDecoder().decode(base64); + } + return new String(decoded, StandardCharsets.UTF_8); + } catch (Exception e) { + throw new IllegalArgumentException("Invalid Base64 string: " + base64.substring(0, 30), e); + } + } + + +} \ No newline at end of file diff --git a/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java b/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java index 11f861d5..f3b495dd 100644 --- a/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java +++ b/flow-engine-framework/src/main/java/com/codingapi/flow/workflow/Workflow.java @@ -373,4 +373,11 @@ public boolean isNextNode(IFlowNode currentNode, IFlowNode nextNode) { public void updateTime() { this.updatedTime = System.currentTimeMillis(); } + + public void resetWorkflow() { + this.id = RandomUtils.generateStringId(); + this.code = RandomUtils.generateWorkflowCode(); + this.createdTime = System.currentTimeMillis(); + this.updateTime(); + } } diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/factory/MyFlowServiceFactory.java b/flow-engine-framework/src/test/java/com/codingapi/flow/factory/MyFlowServiceFactory.java index 781335f9..fa6e3949 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/factory/MyFlowServiceFactory.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/factory/MyFlowServiceFactory.java @@ -1,5 +1,6 @@ package com.codingapi.flow.factory; +import com.codingapi.flow.context.GatewayContext; import com.codingapi.flow.context.RepositoryHolderContext; import com.codingapi.flow.gateway.impl.UserGateway; import com.codingapi.flow.repository.*; @@ -42,6 +43,8 @@ public MyFlowServiceFactory() { RepositoryHolderContext.getInstance().register(workflowService, flowRecordService, userGateway, parallelBranchRepository, delayTaskRepository, urgeIntervalRepository); repositoryHolder = RepositoryHolderContext.getInstance(); this.flowService = new FlowService(this.repositoryHolder); + + GatewayContext.getInstance().setFlowOperatorGateway(userGateway); } } diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowSampleServiceTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowSampleServiceTest.java index cc14b6a3..9ba7d111 100644 --- a/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowSampleServiceTest.java +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowSampleServiceTest.java @@ -111,6 +111,16 @@ void create() { } + @Test + void importWorkflow() { + String data = "data:application/json;base64,eyJ1cGRhdGVkVGltZSI6IjE3NzMyMjI0MzkzMTIiLCJjb2RlIjoicmRZbUt2UzMxOSIsIm5vZGVzIjpbeyJ2aWV3IjoiZGVmYXVsdCIsInN0cmF0ZWdpZXMiOlt7InNjcmlwdCI6Ii8vIEBTQ1JJUFRfVElUTEUg5L2g5pyJ5LiA5p2h5b6F5YqeXG5kZWYgcnVuKHJlcXVlc3Qpe1xuICAgIHJldHVybiAn5L2g5pyJ5LiA5p2h5b6F5YqeJ1xufVxuIiwic3RyYXRlZ3lUeXBlIjoiTm9kZVRpdGxlU3RyYXRlZ3kifSx7InN0cmF0ZWd5VHlwZSI6IkZvcm1GaWVsZFBlcm1pc3Npb25TdHJhdGVneSIsImZpZWxkUGVybWlzc2lvbnMiOltdfSx7ImVuYWJsZSI6dHJ1ZSwidHlwZSI6IlJFVk9LRV9DVVJSRU5UIiwic3RyYXRlZ3lUeXBlIjoiUmV2b2tlU3RyYXRlZ3kifV0sImRpc3BsYXkiOnRydWUsIm5hbWUiOiLlvIDlp4voioLngrkiLCJpZCI6IldSOGNnOTN1c3hqTmxQMXNFVSIsInR5cGUiOiJTVEFSVCIsImFjdGlvbnMiOlt7ImVuYWJsZSI6dHJ1ZSwiZGlzcGxheSI6eyJ0aXRsZSI6IumAmui/hyJ9LCJpZCI6IkJ6UGtWQ3BISUp6WXNaRVJSYiIsInR5cGUiOiJQQVNTIiwidGl0bGUiOiLpgJrov4cifSx7ImVuYWJsZSI6dHJ1ZSwiZGlzcGxheSI6eyJ0aXRsZSI6IuS/neWtmCJ9LCJpZCI6ImgzYmhoQTBGZHlRTUpNUnlBQSIsInR5cGUiOiJTQVZFIiwidGl0bGUiOiLkv53lrZgifV0sIm9yZGVyIjoiMCJ9LHsidmlldyI6ImRlZmF1bHQiLCJzdHJhdGVnaWVzIjpbeyJ0aW1lb3V0VGltZSI6Ijg2NDAwMDAwIiwidHlwZSI6IlJFTUlORCIsInN0cmF0ZWd5VHlwZSI6IlRpbWVvdXRTdHJhdGVneSJ9LHsidHlwZSI6IlNFUVVFTkNFIiwicGVyY2VudCI6IjAuMCIsInN0cmF0ZWd5VHlwZSI6Ik11bHRpT3BlcmF0b3JBdWRpdFN0cmF0ZWd5In0seyJ0eXBlIjoiQVVUT19QQVNTIiwic3RyYXRlZ3lUeXBlIjoiU2FtZU9wZXJhdG9yQXVkaXRTdHJhdGVneSJ9LHsiZW5hYmxlIjpmYWxzZSwic3RyYXRlZ3lUeXBlIjoiUmVjb3JkTWVyZ2VTdHJhdGVneSJ9LHsidHlwZSI6IlJFU1VNRSIsInN0cmF0ZWd5VHlwZSI6IlJlc3VibWl0U3RyYXRlZ3kifSx7InNpZ25SZXF1aXJlZCI6ZmFsc2UsImFkdmljZVJlcXVpcmVkIjpmYWxzZSwic3RyYXRlZ3lUeXBlIjoiQWR2aWNlU3RyYXRlZ3kifSx7InNjcmlwdCI6Ii8vIEBTQ1JJUFRfVElUTEUg5Zue6YCA6Iez5byA5aeL6IqC54K5XG4vLyBAU0NSSVBUX01FVEEge1widHlwZVwiOlwibm9kZVwiLFwibm9kZVwiOlwiU1RBUlRcIn1cbmRlZiBydW4ocmVxdWVzdCl7XG4gICAgcmV0dXJuICRiaW5kLmNyZWF0ZUVycm9yVGhyb3cocmVxdWVzdC5nZXRTdGFydE5vZGUoKSk7XG59XG4iLCJzdHJhdGVneVR5cGUiOiJFcnJvclRyaWdnZXJTdHJhdGVneSJ9LHsic2NyaXB0IjoiLy8gQFNDUklQVF9USVRMRSDkvaDmnInkuIDmnaHlvoXlip5cbmRlZiBydW4ocmVxdWVzdCl7XG4gICAgcmV0dXJuICfkvaDmnInkuIDmnaHlvoXlip4nXG59XG4iLCJzdHJhdGVneVR5cGUiOiJOb2RlVGl0bGVTdHJhdGVneSJ9LHsic3RyYXRlZ3lUeXBlIjoiRm9ybUZpZWxkUGVybWlzc2lvblN0cmF0ZWd5IiwiZmllbGRQZXJtaXNzaW9ucyI6eyIkcmVmIjoiJC5ub2Rlc1swXS5zdHJhdGVnaWVzWzFdLmZpZWxkUGVybWlzc2lvbnMifX0seyJzY3JpcHQiOiIvLyBAU0NSSVBUX1RJVExFIOa1geeoi+WIm+W7uuiAhVxuLy8gQFNDUklQVF9NRVRBIHtcInR5cGVcIjpcImNyZWF0b3JcIn1cbmRlZiBydW4ocmVxdWVzdCl7XG4gICAgcmV0dXJuIFtyZXF1ZXN0LmdldENyZWF0ZWRPcGVyYXRvcigpXVxufVxuIiwic3RyYXRlZ3lUeXBlIjoiT3BlcmF0b3JMb2FkU3RyYXRlZ3kifSx7ImVuYWJsZSI6dHJ1ZSwidHlwZSI6IlJFVk9LRV9DVVJSRU5UIiwic3RyYXRlZ3lUeXBlIjoiUmV2b2tlU3RyYXRlZ3kifV0sImRpc3BsYXkiOnRydWUsIm5hbWUiOiLlrqHmibnoioLngrkiLCJpZCI6IjFNQWNxRkpBbEtCeGNVb2J4MyIsInR5cGUiOiJBUFBST1ZBTCIsImFjdGlvbnMiOlt7ImVuYWJsZSI6dHJ1ZSwiZGlzcGxheSI6eyJ0aXRsZSI6IumAmui/hyJ9LCJpZCI6ImpjWk9IYWlKcnl6SmIyZkZNciIsInR5cGUiOiJQQVNTIiwidGl0bGUiOiLpgJrov4cifSx7ImVuYWJsZSI6dHJ1ZSwiZGlzcGxheSI6eyJ0aXRsZSI6IuaLkue7nSJ9LCJpZCI6ImJ5VVpub2trNnRYVzRrOHlPVyIsInR5cGUiOiJSRUpFQ1QiLCJ0aXRsZSI6IuaLkue7nSIsInNjcmlwdCI6Ii8vIEBTQ1JJUFRfVElUTEUg6L+U5Zue5byA5aeL6IqC54K5XG4vLyBAU0NSSVBUX01FVEEge1widHlwZVwiOlwiU1RBUlRcIn1cbmRlZiBydW4ocmVxdWVzdCl7XG4gICAgcmV0dXJuIHJlcXVlc3QuZ2V0U3RhcnROb2RlKCkuZ2V0SWQoKTtcbn1cbiJ9LHsiZW5hYmxlIjp0cnVlLCJkaXNwbGF5Ijp7InRpdGxlIjoi5L+d5a2YIn0sImlkIjoiUWplQXp3bU1qSFNOWHBiOVBvIiwidHlwZSI6IlNBVkUiLCJ0aXRsZSI6IuS/neWtmCJ9LHsiZW5hYmxlIjp0cnVlLCJkaXNwbGF5Ijp7InRpdGxlIjoi5Yqg562+In0sImlkIjoiUzd4Q09kNHF0ZHRHZDJFbFF3IiwidHlwZSI6IkFERF9BVURJVCIsInRpdGxlIjoi5Yqg562+In0seyJlbmFibGUiOnRydWUsImRpc3BsYXkiOnsidGl0bGUiOiLovazlip4ifSwiaWQiOiJXNmJiM1dWd1JKSlpWNDVzUjMiLCJ0eXBlIjoiVFJBTlNGRVIiLCJ0aXRsZSI6Iui9rOWKniJ9LHsiZW5hYmxlIjp0cnVlLCJkaXNwbGF5Ijp7InRpdGxlIjoi6YCA5ZueIn0sImlkIjoicVphb0djc3ZXNmVtSlZnTU03IiwidHlwZSI6IlJFVFVSTiIsInRpdGxlIjoi6YCA5ZueIn0seyJlbmFibGUiOnRydWUsImRpc3BsYXkiOnsidGl0bGUiOiLlp5TmtL4ifSwiaWQiOiJHTTBtaU1IRWdyV25naU1QRnAiLCJ0eXBlIjoiREVMRUdBVEUiLCJ0aXRsZSI6IuWnlOa0viJ9XSwib3JkZXIiOiIwIn0seyJzdHJhdGVnaWVzIjp7IiRyZWYiOiIkLm5vZGVzWzBdLnN0cmF0ZWdpZXNbMV0uZmllbGRQZXJtaXNzaW9ucyJ9LCJkaXNwbGF5Ijp0cnVlLCJuYW1lIjoi57uT5p2f6IqC54K5IiwiaWQiOiJ4cUttRFBpV3BZbXpFQWlONkoiLCJ0eXBlIjoiRU5EIiwiYWN0aW9ucyI6eyIkcmVmIjoiJC5ub2Rlc1swXS5zdHJhdGVnaWVzWzFdLmZpZWxkUGVybWlzc2lvbnMifSwib3JkZXIiOiIwIn1dLCJmb3JtIjp7ImNvZGUiOiJsZWF2ZSIsIm5hbWUiOiLor7flgYfljZUiLCJmaWVsZHMiOlt7ImNvZGUiOiJkYXlzIiwiaGlkZGVuIjpmYWxzZSwibmFtZSI6IuWkqeaVsCIsImlkIjoiNjhmNjdiODAtODk2YS00MGI5LTk4OGMtYTI2NTI3NjAyNGMyIiwicGxhY2Vob2xkZXIiOiLor7fovpPlhaXlpKnmlbAiLCJ0eXBlIjoiTlVNQkVSIiwicmVxdWlyZWQiOnRydWV9LHsiY29kZSI6ImRlc2MiLCJoaWRkZW4iOmZhbHNlLCJuYW1lIjoi55CG55SxIiwiaWQiOiJmYmJiZGYwNS03NGMwLTQyNDktYmVhYS1hNzdiZDJmN2RlYTQiLCJwbGFjZWhvbGRlciI6Iuivt+i+k+WFpeeQhueUsSIsInR5cGUiOiJTVFJJTkciLCJyZXF1aXJlZCI6dHJ1ZX1dfSwiY3JlYXRlZE9wZXJhdG9yIjoiMSIsInN0cmF0ZWdpZXMiOlt7ImVuYWJsZSI6dHJ1ZSwic3RyYXRlZ3lUeXBlIjoiSW50ZXJmZXJlU3RyYXRlZ3kifSx7ImVuYWJsZSI6dHJ1ZSwiaW50ZXJ2YWwiOiI2MCIsInN0cmF0ZWd5VHlwZSI6IlVyZ2VTdHJhdGVneSJ9XSwiY3JlYXRlZFRpbWUiOiIxNzczMjIyNDAxMzU0IiwiaWQiOiJySUVtbVFFUFR4MWx6MmlSSFoiLCJ0aXRsZSI6Iuivt+WBh+a1geeoiyIsIm9wZXJhdG9yQ3JlYXRlU2NyaXB0IjoiLy8gQFNDUklQVF9USVRMRSDku7vmhI/nlKjmiLdcbi8vIEBTQ1JJUFRfTUVUQSB7XCJ0eXBlXCI6XCJhbnlcIn1cbmRlZiBydW4ocmVxdWVzdCl7XG4gICAgcmV0dXJuIHRydWVcbn1cbiJ9"; + String workId = factory.workflowService.importWorkflow(data); + Workflow workflow = factory.workflowService.getWorkflow(workId); + assertEquals("leave", workflow.getForm().getCode()); + assertEquals("请假流程", workflow.getTitle()); + } + + /** * 全部通过测试 */ diff --git a/flow-engine-framework/src/test/java/com/codingapi/flow/utils/Base64UtilsTest.java b/flow-engine-framework/src/test/java/com/codingapi/flow/utils/Base64UtilsTest.java new file mode 100644 index 00000000..90a8270d --- /dev/null +++ b/flow-engine-framework/src/test/java/com/codingapi/flow/utils/Base64UtilsTest.java @@ -0,0 +1,21 @@ +package com.codingapi.flow.utils; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class Base64UtilsTest { + + @Test + void toJson() { + String data = "data:application/json;base64,eyJ1cGRhdGVkVGltZSI6IjE3NzMyMjI0MzkzMTIiLCJjb2RlIjoicmRZbUt2UzMxOSIsIm5vZGVzIjpbeyJ2aWV3IjoiZGVmYXVsdCIsInN0cmF0ZWdpZXMiOlt7InNjcmlwdCI6Ii8vIEBTQ1JJUFRfVElUTEUg5L2g5pyJ5LiA5p2h5b6F5YqeXG5kZWYgcnVuKHJlcXVlc3Qpe1xuICAgIHJldHVybiAn5L2g5pyJ5LiA5p2h5b6F5YqeJ1xufVxuIiwic3RyYXRlZ3lUeXBlIjoiTm9kZVRpdGxlU3RyYXRlZ3kifSx7InN0cmF0ZWd5VHlwZSI6IkZvcm1GaWVsZFBlcm1pc3Npb25TdHJhdGVneSIsImZpZWxkUGVybWlzc2lvbnMiOltdfSx7ImVuYWJsZSI6dHJ1ZSwidHlwZSI6IlJFVk9LRV9DVVJSRU5UIiwic3RyYXRlZ3lUeXBlIjoiUmV2b2tlU3RyYXRlZ3kifV0sImRpc3BsYXkiOnRydWUsIm5hbWUiOiLlvIDlp4voioLngrkiLCJpZCI6IldSOGNnOTN1c3hqTmxQMXNFVSIsInR5cGUiOiJTVEFSVCIsImFjdGlvbnMiOlt7ImVuYWJsZSI6dHJ1ZSwiZGlzcGxheSI6eyJ0aXRsZSI6IumAmui/hyJ9LCJpZCI6IkJ6UGtWQ3BISUp6WXNaRVJSYiIsInR5cGUiOiJQQVNTIiwidGl0bGUiOiLpgJrov4cifSx7ImVuYWJsZSI6dHJ1ZSwiZGlzcGxheSI6eyJ0aXRsZSI6IuS/neWtmCJ9LCJpZCI6ImgzYmhoQTBGZHlRTUpNUnlBQSIsInR5cGUiOiJTQVZFIiwidGl0bGUiOiLkv53lrZgifV0sIm9yZGVyIjoiMCJ9LHsidmlldyI6ImRlZmF1bHQiLCJzdHJhdGVnaWVzIjpbeyJ0aW1lb3V0VGltZSI6Ijg2NDAwMDAwIiwidHlwZSI6IlJFTUlORCIsInN0cmF0ZWd5VHlwZSI6IlRpbWVvdXRTdHJhdGVneSJ9LHsidHlwZSI6IlNFUVVFTkNFIiwicGVyY2VudCI6IjAuMCIsInN0cmF0ZWd5VHlwZSI6Ik11bHRpT3BlcmF0b3JBdWRpdFN0cmF0ZWd5In0seyJ0eXBlIjoiQVVUT19QQVNTIiwic3RyYXRlZ3lUeXBlIjoiU2FtZU9wZXJhdG9yQXVkaXRTdHJhdGVneSJ9LHsiZW5hYmxlIjpmYWxzZSwic3RyYXRlZ3lUeXBlIjoiUmVjb3JkTWVyZ2VTdHJhdGVneSJ9LHsidHlwZSI6IlJFU1VNRSIsInN0cmF0ZWd5VHlwZSI6IlJlc3VibWl0U3RyYXRlZ3kifSx7InNpZ25SZXF1aXJlZCI6ZmFsc2UsImFkdmljZVJlcXVpcmVkIjpmYWxzZSwic3RyYXRlZ3lUeXBlIjoiQWR2aWNlU3RyYXRlZ3kifSx7InNjcmlwdCI6Ii8vIEBTQ1JJUFRfVElUTEUg5Zue6YCA6Iez5byA5aeL6IqC54K5XG4vLyBAU0NSSVBUX01FVEEge1widHlwZVwiOlwibm9kZVwiLFwibm9kZVwiOlwiU1RBUlRcIn1cbmRlZiBydW4ocmVxdWVzdCl7XG4gICAgcmV0dXJuICRiaW5kLmNyZWF0ZUVycm9yVGhyb3cocmVxdWVzdC5nZXRTdGFydE5vZGUoKSk7XG59XG4iLCJzdHJhdGVneVR5cGUiOiJFcnJvclRyaWdnZXJTdHJhdGVneSJ9LHsic2NyaXB0IjoiLy8gQFNDUklQVF9USVRMRSDkvaDmnInkuIDmnaHlvoXlip5cbmRlZiBydW4ocmVxdWVzdCl7XG4gICAgcmV0dXJuICfkvaDmnInkuIDmnaHlvoXlip4nXG59XG4iLCJzdHJhdGVneVR5cGUiOiJOb2RlVGl0bGVTdHJhdGVneSJ9LHsic3RyYXRlZ3lUeXBlIjoiRm9ybUZpZWxkUGVybWlzc2lvblN0cmF0ZWd5IiwiZmllbGRQZXJtaXNzaW9ucyI6eyIkcmVmIjoiJC5ub2Rlc1swXS5zdHJhdGVnaWVzWzFdLmZpZWxkUGVybWlzc2lvbnMifX0seyJzY3JpcHQiOiIvLyBAU0NSSVBUX1RJVExFIOa1geeoi+WIm+W7uuiAhVxuLy8gQFNDUklQVF9NRVRBIHtcInR5cGVcIjpcImNyZWF0b3JcIn1cbmRlZiBydW4ocmVxdWVzdCl7XG4gICAgcmV0dXJuIFtyZXF1ZXN0LmdldENyZWF0ZWRPcGVyYXRvcigpXVxufVxuIiwic3RyYXRlZ3lUeXBlIjoiT3BlcmF0b3JMb2FkU3RyYXRlZ3kifSx7ImVuYWJsZSI6dHJ1ZSwidHlwZSI6IlJFVk9LRV9DVVJSRU5UIiwic3RyYXRlZ3lUeXBlIjoiUmV2b2tlU3RyYXRlZ3kifV0sImRpc3BsYXkiOnRydWUsIm5hbWUiOiLlrqHmibnoioLngrkiLCJpZCI6IjFNQWNxRkpBbEtCeGNVb2J4MyIsInR5cGUiOiJBUFBST1ZBTCIsImFjdGlvbnMiOlt7ImVuYWJsZSI6dHJ1ZSwiZGlzcGxheSI6eyJ0aXRsZSI6IumAmui/hyJ9LCJpZCI6ImpjWk9IYWlKcnl6SmIyZkZNciIsInR5cGUiOiJQQVNTIiwidGl0bGUiOiLpgJrov4cifSx7ImVuYWJsZSI6dHJ1ZSwiZGlzcGxheSI6eyJ0aXRsZSI6IuaLkue7nSJ9LCJpZCI6ImJ5VVpub2trNnRYVzRrOHlPVyIsInR5cGUiOiJSRUpFQ1QiLCJ0aXRsZSI6IuaLkue7nSIsInNjcmlwdCI6Ii8vIEBTQ1JJUFRfVElUTEUg6L+U5Zue5byA5aeL6IqC54K5XG4vLyBAU0NSSVBUX01FVEEge1widHlwZVwiOlwiU1RBUlRcIn1cbmRlZiBydW4ocmVxdWVzdCl7XG4gICAgcmV0dXJuIHJlcXVlc3QuZ2V0U3RhcnROb2RlKCkuZ2V0SWQoKTtcbn1cbiJ9LHsiZW5hYmxlIjp0cnVlLCJkaXNwbGF5Ijp7InRpdGxlIjoi5L+d5a2YIn0sImlkIjoiUWplQXp3bU1qSFNOWHBiOVBvIiwidHlwZSI6IlNBVkUiLCJ0aXRsZSI6IuS/neWtmCJ9LHsiZW5hYmxlIjp0cnVlLCJkaXNwbGF5Ijp7InRpdGxlIjoi5Yqg562+In0sImlkIjoiUzd4Q09kNHF0ZHRHZDJFbFF3IiwidHlwZSI6IkFERF9BVURJVCIsInRpdGxlIjoi5Yqg562+In0seyJlbmFibGUiOnRydWUsImRpc3BsYXkiOnsidGl0bGUiOiLovazlip4ifSwiaWQiOiJXNmJiM1dWd1JKSlpWNDVzUjMiLCJ0eXBlIjoiVFJBTlNGRVIiLCJ0aXRsZSI6Iui9rOWKniJ9LHsiZW5hYmxlIjp0cnVlLCJkaXNwbGF5Ijp7InRpdGxlIjoi6YCA5ZueIn0sImlkIjoicVphb0djc3ZXNmVtSlZnTU03IiwidHlwZSI6IlJFVFVSTiIsInRpdGxlIjoi6YCA5ZueIn0seyJlbmFibGUiOnRydWUsImRpc3BsYXkiOnsidGl0bGUiOiLlp5TmtL4ifSwiaWQiOiJHTTBtaU1IRWdyV25naU1QRnAiLCJ0eXBlIjoiREVMRUdBVEUiLCJ0aXRsZSI6IuWnlOa0viJ9XSwib3JkZXIiOiIwIn0seyJzdHJhdGVnaWVzIjp7IiRyZWYiOiIkLm5vZGVzWzBdLnN0cmF0ZWdpZXNbMV0uZmllbGRQZXJtaXNzaW9ucyJ9LCJkaXNwbGF5Ijp0cnVlLCJuYW1lIjoi57uT5p2f6IqC54K5IiwiaWQiOiJ4cUttRFBpV3BZbXpFQWlONkoiLCJ0eXBlIjoiRU5EIiwiYWN0aW9ucyI6eyIkcmVmIjoiJC5ub2Rlc1swXS5zdHJhdGVnaWVzWzFdLmZpZWxkUGVybWlzc2lvbnMifSwib3JkZXIiOiIwIn1dLCJmb3JtIjp7ImNvZGUiOiJsZWF2ZSIsIm5hbWUiOiLor7flgYfljZUiLCJmaWVsZHMiOlt7ImNvZGUiOiJkYXlzIiwiaGlkZGVuIjpmYWxzZSwibmFtZSI6IuWkqeaVsCIsImlkIjoiNjhmNjdiODAtODk2YS00MGI5LTk4OGMtYTI2NTI3NjAyNGMyIiwicGxhY2Vob2xkZXIiOiLor7fovpPlhaXlpKnmlbAiLCJ0eXBlIjoiTlVNQkVSIiwicmVxdWlyZWQiOnRydWV9LHsiY29kZSI6ImRlc2MiLCJoaWRkZW4iOmZhbHNlLCJuYW1lIjoi55CG55SxIiwiaWQiOiJmYmJiZGYwNS03NGMwLTQyNDktYmVhYS1hNzdiZDJmN2RlYTQiLCJwbGFjZWhvbGRlciI6Iuivt+i+k+WFpeeQhueUsSIsInR5cGUiOiJTVFJJTkciLCJyZXF1aXJlZCI6dHJ1ZX1dfSwiY3JlYXRlZE9wZXJhdG9yIjoiMSIsInN0cmF0ZWdpZXMiOlt7ImVuYWJsZSI6dHJ1ZSwic3RyYXRlZ3lUeXBlIjoiSW50ZXJmZXJlU3RyYXRlZ3kifSx7ImVuYWJsZSI6dHJ1ZSwiaW50ZXJ2YWwiOiI2MCIsInN0cmF0ZWd5VHlwZSI6IlVyZ2VTdHJhdGVneSJ9XSwiY3JlYXRlZFRpbWUiOiIxNzczMjIyNDAxMzU0IiwiaWQiOiJySUVtbVFFUFR4MWx6MmlSSFoiLCJ0aXRsZSI6Iuivt+WBh+a1geeoiyIsIm9wZXJhdG9yQ3JlYXRlU2NyaXB0IjoiLy8gQFNDUklQVF9USVRMRSDku7vmhI/nlKjmiLdcbi8vIEBTQ1JJUFRfTUVUQSB7XCJ0eXBlXCI6XCJhbnlcIn1cbmRlZiBydW4ocmVxdWVzdCl7XG4gICAgcmV0dXJuIHRydWVcbn1cbiJ9"; + + // Debug output + System.out.println("Input length: " + data.length()); + System.out.println("Input starts with prefix: " + data.startsWith("data:application/json;base64,")); + + String result = Base64Utils.toJson(data); + System.out.println("Result length: " + result.length()); + System.out.println("First 100 chars: " + result.substring(0, Math.min(100, result.length()))); + } +} diff --git a/flow-engine-starter-api/src/main/java/com/codingapi/flow/api/controller/WorkflowController.java b/flow-engine-starter-api/src/main/java/com/codingapi/flow/api/controller/WorkflowController.java index 2b14720f..3938ece9 100644 --- a/flow-engine-starter-api/src/main/java/com/codingapi/flow/api/controller/WorkflowController.java +++ b/flow-engine-starter-api/src/main/java/com/codingapi/flow/api/controller/WorkflowController.java @@ -3,8 +3,7 @@ import com.alibaba.fastjson.JSONObject; import com.codingapi.flow.api.pojo.NodeCreateRequest; import com.codingapi.flow.api.pojo.WorkflowUpdateVersionNameRequest; -import com.codingapi.flow.context.GatewayContext; -import com.codingapi.flow.context.RepositoryHolderContext; +import com.codingapi.flow.exception.FlowPermissionException; import com.codingapi.flow.gateway.FlowOperatorGateway; import com.codingapi.flow.mock.MockInstance; import com.codingapi.flow.mock.MockInstanceFactory; @@ -21,11 +20,15 @@ import com.codingapi.springboot.framework.dto.request.IdRequest; import com.codingapi.springboot.framework.dto.response.Response; import com.codingapi.springboot.framework.dto.response.SingleResponse; +import com.codingapi.springboot.framework.exception.LocaleMessageException; import com.codingapi.springboot.framework.user.UserContext; +import jakarta.servlet.http.HttpServletResponse; import lombok.AllArgsConstructor; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.Map; @@ -79,7 +82,13 @@ public Response changeState(@RequestBody IdRequest request) { @PostMapping("/mock") public SingleResponse mock() { - MockInstance mockInstance = MockInstanceFactory.getInstance().create(flowOperatorGateway,workflowRepository); + IFlowOperator current = (IFlowOperator) UserContext.getInstance().current(); + if (current != null) { + if (!current.isFlowManager()) { + throw FlowPermissionException.accessDenied(current.getName()); + } + } + MockInstance mockInstance = MockInstanceFactory.getInstance().create(flowOperatorGateway, workflowRepository); return SingleResponse.of(mockInstance.getMockKey()); } @@ -89,7 +98,6 @@ public Response mock(@RequestBody IdRequest request) { return Response.buildSuccess(); } - @PostMapping("/create") public SingleResponse create() { Workflow workflow = WorkflowBuilder.builder() @@ -99,6 +107,28 @@ public SingleResponse create() { return SingleResponse.of(jsonObject); } + @PostMapping("/import") + public SingleResponse importWorkflow(@RequestBody JSONObject body) { + String workId = workflowService.importWorkflow(body.getString("file")); + return SingleResponse.of(workId); + } + + @GetMapping("/export") + public void export(IdRequest request, HttpServletResponse response) { + Workflow workflow = workflowService.getWorkflow(request.getStringId()); + JSONObject jsonObject = JSONObject.parseObject(workflow.toJson()); + try { + response.setContentType("application/json;charset=UTF-8"); + response.setCharacterEncoding("UTF-8"); + String fileName = URLEncoder.encode("workflow_" + request.getStringId() + ".json", StandardCharsets.UTF_8); + response.setHeader("Content-Disposition", "attachment;filename=" + fileName); + response.getWriter().write(jsonObject.toJSONString()); + response.getWriter().flush(); + } catch (Exception e) { + throw new LocaleMessageException("export.error", e); + } + } + @PostMapping("/create-node") public SingleResponse> createNode(@RequestBody NodeCreateRequest request) { NodeType type = NodeType.valueOf(request.getType()); @@ -121,7 +151,7 @@ public Response save(@RequestBody JSONObject request) { if (StringUtils.hasText(versionName)) { WorkflowVersion workflowVersion = new WorkflowVersion(workflow); workflowVersion.setVersionName(versionName); - workflowService.saveWorkflowVersion(workflowVersion,true); + workflowService.saveWorkflowVersion(workflowVersion, true); } else { workflowService.saveWorkflow(workflow); } diff --git a/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/repository/impl/WorkflowVersionRepositoryImpl.java b/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/repository/impl/WorkflowVersionRepositoryImpl.java index 9c58ba48..4150eb9a 100644 --- a/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/repository/impl/WorkflowVersionRepositoryImpl.java +++ b/flow-engine-starter-infra/src/main/java/com/codingapi/flow/infra/repository/impl/WorkflowVersionRepositoryImpl.java @@ -5,10 +5,12 @@ import com.codingapi.flow.infra.jpa.WorkflowVersionEntityRepository; import com.codingapi.flow.repository.WorkflowVersionRepository; import com.codingapi.flow.workflow.WorkflowVersion; +import jakarta.transaction.Transactional; import lombok.AllArgsConstructor; import java.util.List; +@Transactional @AllArgsConstructor public class WorkflowVersionRepositoryImpl implements WorkflowVersionRepository { diff --git a/flow-frontend b/flow-frontend index a4ed08ee..4e3b3856 160000 --- a/flow-frontend +++ b/flow-frontend @@ -1 +1 @@ -Subproject commit a4ed08ee5b83759ddb1a3485157ad412e4a9baf7 +Subproject commit 4e3b38568382a5bb5621805b0c6452066d7353d0