fix: 收紧智能体聊天历史访问范围
- 普通账号仅可访问本人 Agent 会话 - 超级管理员保留全量查询并限制筛选入口
This commit is contained in:
@@ -16,6 +16,7 @@ import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.system.service.CategoryPermissionService;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
@@ -25,37 +26,108 @@ import java.util.List;
|
||||
public class ChatHistoryController {
|
||||
|
||||
private final ChatHistoryManageService chatHistoryManageService;
|
||||
private final CategoryPermissionService categoryPermissionService;
|
||||
|
||||
public ChatHistoryController(ChatHistoryManageService chatHistoryManageService) {
|
||||
/**
|
||||
* 创建聊天历史控制器。
|
||||
*
|
||||
* @param chatHistoryManageService 聊天历史管理服务
|
||||
* @param categoryPermissionService 账号权限服务
|
||||
*/
|
||||
public ChatHistoryController(ChatHistoryManageService chatHistoryManageService,
|
||||
CategoryPermissionService categoryPermissionService) {
|
||||
this.chatHistoryManageService = chatHistoryManageService;
|
||||
this.categoryPermissionService = categoryPermissionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询当前账号可见的 Agent 会话。
|
||||
*
|
||||
* @param query 会话筛选条件
|
||||
* @return 会话分页结果
|
||||
*/
|
||||
@GetMapping("/sessions")
|
||||
public Result<ChatSessionPage> listSessions(ChatSessionFilterQuery query) {
|
||||
return Result.ok(chatHistoryManageService.queryAdminSessions(query));
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
return Result.ok(chatHistoryManageService.queryAdminSessions(
|
||||
account.getId(),
|
||||
categoryPermissionService.isSuperAdmin(account),
|
||||
query
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前账号可见的 Agent 会话详情。
|
||||
*
|
||||
* @param sessionId 会话 ID
|
||||
* @return 会话详情
|
||||
*/
|
||||
@GetMapping("/sessions/{sessionId}")
|
||||
public Result<ChatSessionSummary> getSession(@PathVariable BigInteger sessionId) {
|
||||
return Result.ok(chatHistoryManageService.getAdminSession(sessionId));
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
return Result.ok(chatHistoryManageService.getAdminSession(
|
||||
account.getId(),
|
||||
categoryPermissionService.isSuperAdmin(account),
|
||||
sessionId
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询当前账号可见会话的消息。
|
||||
*
|
||||
* @param sessionId 会话 ID
|
||||
* @param query 消息分页条件
|
||||
* @return 消息分页结果
|
||||
*/
|
||||
@GetMapping("/sessions/{sessionId}/messages")
|
||||
public Result<ChatHistoryPage> queryMessages(@PathVariable BigInteger sessionId, ChatPageQuery query) {
|
||||
return Result.ok(chatHistoryManageService.queryAdminMessages(sessionId, query));
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
return Result.ok(chatHistoryManageService.queryAdminMessages(
|
||||
account.getId(),
|
||||
categoryPermissionService.isSuperAdmin(account),
|
||||
sessionId,
|
||||
query
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前账号可见会话的答案版本。
|
||||
*
|
||||
* @param sessionId 会话 ID
|
||||
* @param roundId 对话轮次 ID
|
||||
* @return 答案版本列表
|
||||
*/
|
||||
@GetMapping("/sessions/{sessionId}/rounds/{roundId}/variants")
|
||||
public Result<List<ChatMessageRecord>> listRoundVariants(@PathVariable BigInteger sessionId,
|
||||
@PathVariable BigInteger roundId) {
|
||||
return Result.ok(chatHistoryManageService.listAdminRoundVariants(sessionId, roundId));
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
return Result.ok(chatHistoryManageService.listAdminRoundVariants(
|
||||
account.getId(),
|
||||
categoryPermissionService.isSuperAdmin(account),
|
||||
sessionId,
|
||||
roundId
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择当前账号可见会话的答案版本。
|
||||
*
|
||||
* @param sessionId 会话 ID
|
||||
* @param roundId 对话轮次 ID
|
||||
* @param variantIndex 目标版本索引
|
||||
* @return 选中的答案记录
|
||||
*/
|
||||
@PostMapping("/sessions/{sessionId}/rounds/{roundId}/selectVariant")
|
||||
public Result<ChatMessageRecord> selectRoundVariant(@PathVariable BigInteger sessionId,
|
||||
@PathVariable BigInteger roundId,
|
||||
@JsonBody(value = "variantIndex", required = true) Integer variantIndex) {
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
return Result.ok(chatHistoryManageService.selectAdminRoundVariant(sessionId, roundId, variantIndex, account.getId()));
|
||||
return Result.ok(chatHistoryManageService.selectAdminRoundVariant(
|
||||
account.getId(),
|
||||
categoryPermissionService.isSuperAdmin(account),
|
||||
sessionId,
|
||||
roundId,
|
||||
variantIndex
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import org.mockito.MockedStatic;
|
||||
import org.testng.annotations.Test;
|
||||
import tech.easyflow.chatlog.domain.dto.ChatSessionPage;
|
||||
import tech.easyflow.chatlog.domain.dto.ChatSessionSummary;
|
||||
import tech.easyflow.chatlog.domain.query.ChatSessionFilterQuery;
|
||||
import tech.easyflow.chatlog.service.ChatHistoryManageService;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.system.service.CategoryPermissionService;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* {@link ChatHistoryController} 数据范围测试。
|
||||
*/
|
||||
public class ChatHistoryControllerTest {
|
||||
|
||||
/**
|
||||
* 验证普通账号查询时将本人范围传给服务层。
|
||||
*/
|
||||
@Test
|
||||
public void listSessionsShouldUseCurrentUserScopeForRegularAccount() {
|
||||
BigInteger accountId = BigInteger.valueOf(20);
|
||||
ChatHistoryManageService service = mock(ChatHistoryManageService.class);
|
||||
CategoryPermissionService permissionService = mock(CategoryPermissionService.class);
|
||||
ChatHistoryController controller = new ChatHistoryController(service, permissionService);
|
||||
ChatSessionFilterQuery query = new ChatSessionFilterQuery();
|
||||
LoginAccount account = loginAccount(accountId);
|
||||
when(permissionService.isSuperAdmin(account)).thenReturn(false);
|
||||
when(service.queryAdminSessions(accountId, false, query)).thenReturn(new ChatSessionPage());
|
||||
|
||||
try (MockedStatic<SaTokenUtil> saToken = mockStatic(SaTokenUtil.class)) {
|
||||
saToken.when(SaTokenUtil::getLoginAccount).thenReturn(account);
|
||||
|
||||
controller.listSessions(query);
|
||||
}
|
||||
|
||||
verify(service).queryAdminSessions(accountId, false, query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证超级管理员查询详情时保留全量范围。
|
||||
*/
|
||||
@Test
|
||||
public void getSessionShouldUseAllScopeForSuperAdmin() {
|
||||
BigInteger accountId = BigInteger.ONE;
|
||||
BigInteger sessionId = BigInteger.valueOf(30);
|
||||
ChatHistoryManageService service = mock(ChatHistoryManageService.class);
|
||||
CategoryPermissionService permissionService = mock(CategoryPermissionService.class);
|
||||
ChatHistoryController controller = new ChatHistoryController(service, permissionService);
|
||||
LoginAccount account = loginAccount(accountId);
|
||||
when(permissionService.isSuperAdmin(account)).thenReturn(true);
|
||||
when(service.getAdminSession(accountId, true, sessionId)).thenReturn(new ChatSessionSummary());
|
||||
|
||||
try (MockedStatic<SaTokenUtil> saToken = mockStatic(SaTokenUtil.class)) {
|
||||
saToken.when(SaTokenUtil::getLoginAccount).thenReturn(account);
|
||||
|
||||
controller.getSession(sessionId);
|
||||
}
|
||||
|
||||
verify(service).getAdminSession(accountId, true, sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造登录账号。
|
||||
*
|
||||
* @param accountId 账号 ID
|
||||
* @return 登录账号
|
||||
*/
|
||||
private LoginAccount loginAccount(BigInteger accountId) {
|
||||
LoginAccount account = new LoginAccount();
|
||||
account.setId(accountId);
|
||||
return account;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user