feat: 完成分享、单会话与发布审批改造
- 增加工作流协作分享与知识库卡片分享入口,统一低版本浏览器复制反馈 - Web 新登录替换旧会话,并保持 API Key 会话隔离 - 发布审批增加必填说明并在审批详情展示 - 账号重置与导入改用可配置默认强密码
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* {@link WorkflowShareController} 分享地址构建测试。
|
||||
*/
|
||||
public class WorkflowShareControllerTest {
|
||||
|
||||
/**
|
||||
* 验证分享地址保留前端部署基路径。
|
||||
*
|
||||
* @throws Exception 反射调用失败时抛出
|
||||
*/
|
||||
@Test
|
||||
public void shouldPreserveFrontendBasePathFromReferer() throws Exception {
|
||||
HttpServletRequest request = request(Map.of(
|
||||
"referer",
|
||||
"https://example.test/easyflow/ai/workflow?page=1"
|
||||
));
|
||||
|
||||
Assert.assertEquals(
|
||||
buildShareBaseUrl(request),
|
||||
"https://example.test/easyflow/ai/workflow/design"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证反向代理头用于构建外部 HTTPS 分享地址。
|
||||
*
|
||||
* @throws Exception 反射调用失败时抛出
|
||||
*/
|
||||
@Test
|
||||
public void shouldUseForwardedOriginAndPrefix() throws Exception {
|
||||
HttpServletRequest request = request(Map.of(
|
||||
"x-forwarded-proto", "https",
|
||||
"x-forwarded-host", "example.test",
|
||||
"x-forwarded-prefix", "/easyflow"
|
||||
));
|
||||
|
||||
Assert.assertEquals(
|
||||
buildShareBaseUrl(request),
|
||||
"https://example.test/easyflow/ai/workflow/design"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用控制器的分享基础地址构建方法。
|
||||
*
|
||||
* @param request 模拟 HTTP 请求
|
||||
* @return 分享基础地址
|
||||
* @throws Exception 反射调用失败时抛出
|
||||
*/
|
||||
private String buildShareBaseUrl(HttpServletRequest request) throws Exception {
|
||||
Method method = WorkflowShareController.class.getDeclaredMethod(
|
||||
"buildShareBaseUrl",
|
||||
HttpServletRequest.class
|
||||
);
|
||||
method.setAccessible(true);
|
||||
return (String) method.invoke(new WorkflowShareController(), request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建仅提供请求头能力的轻量 Servlet 请求代理。
|
||||
*
|
||||
* @param headers 小写请求头映射
|
||||
* @return HTTP 请求代理
|
||||
*/
|
||||
private HttpServletRequest request(Map<String, String> headers) {
|
||||
return (HttpServletRequest) Proxy.newProxyInstance(
|
||||
getClass().getClassLoader(),
|
||||
new Class<?>[]{HttpServletRequest.class},
|
||||
(proxy, method, args) -> {
|
||||
if ("getHeader".equals(method.getName())) {
|
||||
String name = String.valueOf(args[0]).toLowerCase(Locale.ROOT);
|
||||
return headers.get(name);
|
||||
}
|
||||
return defaultValue(method.getReturnType());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回代理方法所需的基础类型默认值。
|
||||
*
|
||||
* @param returnType 返回值类型
|
||||
* @return 对应默认值
|
||||
*/
|
||||
private Object defaultValue(Class<?> returnType) {
|
||||
if (!returnType.isPrimitive()) {
|
||||
return null;
|
||||
}
|
||||
if (boolean.class == returnType) {
|
||||
return false;
|
||||
}
|
||||
if (char.class == returnType) {
|
||||
return '\0';
|
||||
}
|
||||
if (byte.class == returnType) {
|
||||
return (byte) 0;
|
||||
}
|
||||
if (short.class == returnType) {
|
||||
return (short) 0;
|
||||
}
|
||||
if (int.class == returnType) {
|
||||
return 0;
|
||||
}
|
||||
if (long.class == returnType) {
|
||||
return 0L;
|
||||
}
|
||||
if (float.class == returnType) {
|
||||
return 0F;
|
||||
}
|
||||
return 0D;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user