feat: 完成分享、单会话与发布审批改造
- 增加工作流协作分享与知识库卡片分享入口,统一低版本浏览器复制反馈 - Web 新登录替换旧会话,并保持 API Key 会话隔离 - 发布审批增加必填说明并在审批详情展示 - 账号重置与导入改用可配置默认强密码
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
package tech.easyflow.ai.share;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* V34 工作流分享与审批说明迁移契约测试。
|
||||
*/
|
||||
public class WorkflowShareMigrationContractTest {
|
||||
|
||||
/**
|
||||
* 验证迁移同时创建审批说明、工作流修订号和分享记录所需字段及索引。
|
||||
*
|
||||
* @throws Exception 迁移文件不可读时抛出
|
||||
*/
|
||||
@Test
|
||||
public void migrationShouldCreateWorkflowShareContracts() throws Exception {
|
||||
String sql = migrationSql();
|
||||
|
||||
assertTrue(sql.contains("ADD COLUMN `application_reason` VARCHAR(500)"));
|
||||
assertTrue(sql.contains("ADD COLUMN `revision` INT NOT NULL DEFAULT 0"));
|
||||
assertTrue(sql.contains("CREATE TABLE `tb_workflow_share`"));
|
||||
assertTrue(sql.contains("`share_key_hash` VARCHAR(64) NOT NULL"));
|
||||
assertTrue(sql.contains("`status` VARCHAR(32) NOT NULL"));
|
||||
assertTrue(sql.contains("`dept_id` BIGINT UNSIGNED NULL"));
|
||||
assertTrue(sql.contains("`modified` DATETIME NULL"));
|
||||
assertTrue(sql.contains("UNIQUE INDEX `uni_workflow_share_key_hash`"));
|
||||
assertTrue(sql.contains("INDEX `idx_workflow_share_status` (`workflow_id`, `status`)"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取工作区中的 V34 MySQL 迁移。
|
||||
*
|
||||
* @return 迁移 SQL
|
||||
* @throws Exception 迁移文件不存在或不可读时抛出
|
||||
*/
|
||||
private String migrationSql() throws Exception {
|
||||
Path root = Path.of(System.getProperty("maven.multiModuleProjectDirectory",
|
||||
Path.of(System.getProperty("user.dir")).toAbsolutePath().toString()));
|
||||
while (root != null) {
|
||||
Path migration = root.resolve("easyflow-starter/easyflow-starter-all/src/main/resources/"
|
||||
+ "db/migration/mysql/V34__mysql_workflow_share_and_approval_reason.sql");
|
||||
if (Files.isRegularFile(migration)) {
|
||||
return Files.readString(migration, StandardCharsets.UTF_8);
|
||||
}
|
||||
root = root.getParent();
|
||||
}
|
||||
throw new IllegalStateException("找不到 V34 工作流分享与审批说明迁移");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package tech.easyflow.ai.share;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import tech.easyflow.system.enums.ResourceAction;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* {@link WorkflowSharePolicy} 测试。
|
||||
*/
|
||||
public class WorkflowSharePolicyTest {
|
||||
|
||||
/**
|
||||
* 验证相同密钥生成稳定的 SHA-256 摘要。
|
||||
*/
|
||||
@Test
|
||||
public void shouldHashShareKeyDeterministically() {
|
||||
String first = WorkflowSharePolicy.hashShareKey("share-key");
|
||||
String second = WorkflowSharePolicy.hashShareKey("share-key");
|
||||
|
||||
Assert.assertEquals(first, second);
|
||||
Assert.assertEquals(64, first.length());
|
||||
Assert.assertNotEquals("share-key", first);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证默认过期时间为创建时间后 30 分钟。
|
||||
*/
|
||||
@Test
|
||||
public void shouldExpireThirtyMinutesAfterCreation() {
|
||||
Date createdAt = new Date(1_000L);
|
||||
|
||||
Date expiresAt = WorkflowSharePolicy.defaultExpiresAt(createdAt);
|
||||
|
||||
Assert.assertEquals(30 * 60 * 1_000L, expiresAt.getTime() - createdAt.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证分享授权仅覆盖编辑、运行和发布所需接口。
|
||||
*/
|
||||
@Test
|
||||
public void shouldAllowOnlyCollaborativeWorkflowOperations() {
|
||||
Assert.assertTrue(WorkflowSharePolicy.isAllowedRequest(
|
||||
"GET",
|
||||
"/api/v1/workflow/detail",
|
||||
ResourceAction.READ
|
||||
));
|
||||
Assert.assertTrue(WorkflowSharePolicy.isAllowedRequest(
|
||||
"POST",
|
||||
"/api/v1/workflow/update",
|
||||
ResourceAction.MANAGE
|
||||
));
|
||||
Assert.assertTrue(WorkflowSharePolicy.isAllowedRequest(
|
||||
"POST",
|
||||
"/api/v1/workflow/runAsync",
|
||||
ResourceAction.USE
|
||||
));
|
||||
Assert.assertTrue(WorkflowSharePolicy.isAllowedRequest(
|
||||
"POST",
|
||||
"/api/v1/workflow/submitPublishApproval",
|
||||
ResourceAction.MANAGE
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证删除、下线和再次分享不在协作授权范围内。
|
||||
*/
|
||||
@Test
|
||||
public void shouldRejectSensitiveWorkflowOperations() {
|
||||
Assert.assertFalse(WorkflowSharePolicy.isAllowedRequest(
|
||||
"POST",
|
||||
"/api/v1/workflow/submitDeleteApproval",
|
||||
ResourceAction.MANAGE
|
||||
));
|
||||
Assert.assertFalse(WorkflowSharePolicy.isAllowedRequest(
|
||||
"POST",
|
||||
"/api/v1/workflow/submitOfflineApproval",
|
||||
ResourceAction.MANAGE
|
||||
));
|
||||
Assert.assertFalse(WorkflowSharePolicy.isAllowedRequest(
|
||||
"POST",
|
||||
"/api/v1/workflowShare/url/create",
|
||||
ResourceAction.MANAGE
|
||||
));
|
||||
Assert.assertFalse(WorkflowSharePolicy.isAllowedRequest(
|
||||
"GET",
|
||||
"/api/v1/workflow/update",
|
||||
ResourceAction.MANAGE
|
||||
));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user