mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-26 13:19:34 +07:00
🌐 chore: translate non-English comments to English in openapi-services (#12993)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -93,15 +93,15 @@ export abstract class BaseService implements IBaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一错误处理方法
|
||||
* @param error 捕获的错误
|
||||
* @param operation 操作名称
|
||||
* @param fallbackMessage 默认错误消息
|
||||
* Unified error handling method
|
||||
* @param error Caught error
|
||||
* @param operation Operation name
|
||||
* @param fallbackMessage Default error message
|
||||
*/
|
||||
protected handleServiceError(error: unknown, operation: string): never {
|
||||
this.log('error', `${operation}失败`, { error });
|
||||
|
||||
// 如果是已知的业务错误,直接抛出
|
||||
// If it is a known business error, throw it directly
|
||||
if (
|
||||
error instanceof Error &&
|
||||
[
|
||||
@@ -117,7 +117,7 @@ export abstract class BaseService implements IBaseService {
|
||||
|
||||
const errorMessage = `${operation}失败: ${error instanceof Error ? error.message : '未知错误'}`;
|
||||
|
||||
// 其他错误统一包装为业务错误
|
||||
// Wrap all other errors as business errors
|
||||
throw this.createBusinessError(errorMessage);
|
||||
}
|
||||
|
||||
@@ -151,9 +151,9 @@ export abstract class BaseService implements IBaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否有全局权限 ALL
|
||||
* @param permissionKey 权限键名
|
||||
* @returns 是否有权限
|
||||
* Check whether the user has global ALL permission
|
||||
* @param permissionKey Permission key name
|
||||
* @returns Whether the user has the permission
|
||||
*/
|
||||
protected async hasGlobalPermission(
|
||||
permissionKey: keyof typeof PERMISSION_ACTIONS,
|
||||
@@ -165,9 +165,9 @@ export abstract class BaseService implements IBaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否有 owner 权限
|
||||
* @param permissionKey 权限键名
|
||||
* @returns 是否有权限
|
||||
* Check whether the user has owner permission
|
||||
* @param permissionKey Permission key name
|
||||
* @returns Whether the user has the permission
|
||||
*/
|
||||
protected async hasOwnerPermission(
|
||||
permissionKey: keyof typeof PERMISSION_ACTIONS,
|
||||
@@ -179,26 +179,26 @@ export abstract class BaseService implements IBaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取资源所属用户 ID
|
||||
* @param target 目标资源的条件信息,如果没有传入,则默认查询范围为当前用户,如果传入 ALL,则返回默认全量查询
|
||||
* @returns 资源所属用户 ID
|
||||
* Get the user ID that a resource belongs to
|
||||
* @param target Target resource condition. If not provided, defaults to current user scope. If ALL is passed, returns full data query.
|
||||
* @returns The user ID the resource belongs to
|
||||
*/
|
||||
protected async getResourceBelongTo(
|
||||
target?: TTarget | typeof ALL_SCOPE,
|
||||
): Promise<string | undefined | null> {
|
||||
// 查询全量数据,则直接返回undefined
|
||||
// Query all data, return undefined directly
|
||||
if (target === ALL_SCOPE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果目标条件为空,默认查询范围为当前用户
|
||||
// If target condition is empty, default scope is current user
|
||||
if (!target || isNilOrEmptyObject(target)) {
|
||||
return this.userId;
|
||||
}
|
||||
|
||||
try {
|
||||
switch (true) {
|
||||
// 查询 sessions 表
|
||||
// Query sessions table
|
||||
case !!target?.targetSessionId: {
|
||||
const targetSession = await this.db.query.sessions.findFirst({
|
||||
columns: { userId: true },
|
||||
@@ -207,7 +207,7 @@ export abstract class BaseService implements IBaseService {
|
||||
return targetSession?.userId;
|
||||
}
|
||||
|
||||
// 查询 agents 表
|
||||
// Query agents table
|
||||
case !!target?.targetAgentId: {
|
||||
const targetAgent = await this.db.query.agents.findFirst({
|
||||
columns: { userId: true },
|
||||
@@ -217,7 +217,7 @@ export abstract class BaseService implements IBaseService {
|
||||
return targetAgent?.userId;
|
||||
}
|
||||
|
||||
// 查询 topics 表
|
||||
// Query topics table
|
||||
case !!target?.targetTopicId: {
|
||||
const targetTopic = await this.db.query.topics.findFirst({
|
||||
columns: { userId: true },
|
||||
@@ -226,7 +226,7 @@ export abstract class BaseService implements IBaseService {
|
||||
return targetTopic?.userId;
|
||||
}
|
||||
|
||||
// 查询 providers 表
|
||||
// Query providers table
|
||||
case !!target?.targetProviderId: {
|
||||
const currentUserProvider = await this.db.query.aiProviders.findFirst({
|
||||
columns: { userId: true },
|
||||
@@ -247,12 +247,12 @@ export abstract class BaseService implements IBaseService {
|
||||
return targetProvider?.userId;
|
||||
}
|
||||
|
||||
// 直接传递 targetUserId 的情况
|
||||
// Case where targetUserId is passed directly
|
||||
case !!target?.targetUserId: {
|
||||
return target.targetUserId;
|
||||
}
|
||||
|
||||
// 查询 knowledgeBases 表
|
||||
// Query knowledgeBases table
|
||||
case !!target?.targetKnowledgeBaseId: {
|
||||
const targetKnowledgeBase = await this.db.query.knowledgeBases.findFirst({
|
||||
columns: { userId: true },
|
||||
@@ -261,7 +261,7 @@ export abstract class BaseService implements IBaseService {
|
||||
return targetKnowledgeBase?.userId;
|
||||
}
|
||||
|
||||
// 查询 files 表
|
||||
// Query files table
|
||||
case !!target?.targetFileId: {
|
||||
const targetFile = await this.db.query.files.findFirst({
|
||||
columns: { userId: true },
|
||||
@@ -270,7 +270,7 @@ export abstract class BaseService implements IBaseService {
|
||||
return targetFile?.userId;
|
||||
}
|
||||
|
||||
// 查询 messages 表
|
||||
// Query messages table
|
||||
case !!target?.targetMessageId: {
|
||||
const targetMessage = await this.db.query.messages.findFirst({
|
||||
columns: { userId: true },
|
||||
@@ -279,7 +279,7 @@ export abstract class BaseService implements IBaseService {
|
||||
return targetMessage?.userId;
|
||||
}
|
||||
|
||||
// 查询 aiModels 表
|
||||
// Query aiModels table
|
||||
case !!target?.targetModelId: {
|
||||
const targetModel = await this.db.query.aiModels.findFirst({
|
||||
columns: { userId: true },
|
||||
@@ -299,19 +299,19 @@ export abstract class BaseService implements IBaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析权限并返回目标信息
|
||||
* 用于处理数据访问权限的通用逻辑,支持以下场景:
|
||||
* 1. 查询/操作当前用户的数据:需要 ALL/owner 权限
|
||||
* 2. 查询/操作指定用户的数据:需要 ALL 权限
|
||||
* 3. 查询/操作所有数据:需要 ALL 权限
|
||||
* Resolve permissions and return target info
|
||||
* Common logic for handling data access permissions, supporting the following scenarios:
|
||||
* 1. Query/operate on current user's data: requires ALL/owner permission
|
||||
* 2. Query/operate on a specific user's data: requires ALL permission
|
||||
* 3. Query/operate on all data: requires ALL permission
|
||||
*
|
||||
* @param permissionKey - 权限键名
|
||||
* @param targetInfoId - 目标ID,可选。传入字符串表示查询/操作特定用户的数据,传入对象键值表示查询/操作特定对象的数据
|
||||
* @param queryAll - 是否查询所有数据,可选。如果提供,表示要查询所有数据,否则只查询当前用户的数据
|
||||
* @returns 返回权限检查结果和查询/操作条件
|
||||
* - isPermitted: 是否允许查询/操作
|
||||
* - condition: 目标信息,包含 userId 过滤条件
|
||||
* - message: 权限被拒绝时的错误信息
|
||||
* @param permissionKey - Permission key name
|
||||
* @param targetInfoId - Target ID, optional. A string means query/operate on a specific user's data; an object key-value means query/operate on a specific object's data
|
||||
* @param queryAll - Whether to query all data, optional. If provided, queries all data; otherwise only queries current user's data
|
||||
* @returns Returns permission check result and query/operation condition
|
||||
* - isPermitted: Whether query/operation is permitted
|
||||
* - condition: Target info containing userId filter
|
||||
* - message: Error message when permission is denied
|
||||
*/
|
||||
protected async resolveOperationPermission(
|
||||
permissionKey: keyof typeof PERMISSION_ACTIONS,
|
||||
@@ -321,13 +321,13 @@ export abstract class BaseService implements IBaseService {
|
||||
isPermitted: boolean;
|
||||
message?: string;
|
||||
}> {
|
||||
// 检查是否有对应动作的 ALL 权限
|
||||
// Check if the user has ALL permission for the corresponding action
|
||||
const hasGlobalAccess = await this.hasGlobalPermission(permissionKey);
|
||||
|
||||
// 获取目标资源所属用户 ID
|
||||
// Get the user ID that the target resource belongs to
|
||||
const resourceBelongTo = await this.getResourceBelongTo(resourceInfo);
|
||||
|
||||
// 记录用户希望访问的资源与当前用户信息
|
||||
// Log the resource the user wants to access and current user info
|
||||
const logContext = {
|
||||
resourceInfo,
|
||||
userId: this.userId,
|
||||
@@ -336,7 +336,7 @@ export abstract class BaseService implements IBaseService {
|
||||
this.log('info', '权限检查', logContext);
|
||||
|
||||
/**
|
||||
* 当用户拥有 ALL 权限时,直接通过校验
|
||||
* When the user has ALL permission, pass the check directly
|
||||
*/
|
||||
if (hasGlobalAccess) {
|
||||
this.log('info', `权限通过:当前user拥有 ${permissionKey} 的最高权限`, logContext);
|
||||
@@ -347,9 +347,9 @@ export abstract class BaseService implements IBaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 当用户没有 ALL 权限时,以下场景不允许操作:
|
||||
* 1. 查询的是全量数据
|
||||
* 2. 查询的是指定用户的数据,但目标资源不属于当前用户
|
||||
* When the user does not have ALL permission, the following scenarios are not allowed:
|
||||
* 1. Querying all data
|
||||
* 2. Querying a specific user's data, but the target resource does not belong to the current user
|
||||
*/
|
||||
if (!resourceBelongTo || resourceBelongTo !== this.userId) {
|
||||
this.log('warn', '权限拒绝:当前user没有ALL权限,或目标资源不属于当前用户', logContext);
|
||||
@@ -360,11 +360,11 @@ export abstract class BaseService implements IBaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 当查询的目标资源属于当前用户时,只要有任意权限就允许操作
|
||||
* 由于 ALL 权限已经在前面校验过,所以这里只需要检查 owner 权限
|
||||
* When the target resource belongs to the current user, any permission allows the operation
|
||||
* Since ALL permission was already checked above, only owner permission needs to be checked here
|
||||
*/
|
||||
if (resourceBelongTo === this.userId) {
|
||||
// 检查是否有对应动作的 owner 权限
|
||||
// Check if the user has owner permission for the corresponding action
|
||||
const hasOwnerAccess = await this.hasOwnerPermission(permissionKey);
|
||||
|
||||
if (hasOwnerAccess) {
|
||||
@@ -382,7 +382,7 @@ export abstract class BaseService implements IBaseService {
|
||||
};
|
||||
}
|
||||
|
||||
// 如果走到这里,走兜底逻辑
|
||||
// If we reach here, apply fallback logic
|
||||
this.log('info', `兜底: no permission`, logContext);
|
||||
return {
|
||||
isPermitted: false,
|
||||
@@ -391,15 +391,15 @@ export abstract class BaseService implements IBaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析批量操作的权限
|
||||
* 用于处理批量数据访问权限的通用逻辑
|
||||
* 1. 批量操作必须要有 ALL 权限
|
||||
* 2. 如果所有资源都属于当前用户,且有 owner 权限,也允许操作
|
||||
* 3. 如果有 ALL 权限,允许操作所有指定的资源
|
||||
* Resolve permissions for batch operations
|
||||
* Common logic for handling batch data access permissions
|
||||
* 1. Batch operations require ALL permission
|
||||
* 2. If all resources belong to the current user and the user has owner permission, the operation is also allowed
|
||||
* 3. If the user has ALL permission, all specified resources can be operated on
|
||||
*
|
||||
* @param permissionKey - 权限键名
|
||||
* @param targetInfoIds - 目标资源 ID 数组
|
||||
* @returns 返回权限检查结果
|
||||
* @param permissionKey - Permission key name
|
||||
* @param targetInfoIds - Array of target resource IDs
|
||||
* @returns Returns the permission check result
|
||||
*/
|
||||
protected async resolveBatchQueryPermission(
|
||||
permissionKey: keyof typeof PERMISSION_ACTIONS,
|
||||
@@ -409,19 +409,19 @@ export abstract class BaseService implements IBaseService {
|
||||
isPermitted: boolean;
|
||||
message?: string;
|
||||
}> {
|
||||
// 先检查是否有全局权限,如果有则直接通过
|
||||
// First check if the user has global permission; if so, pass directly
|
||||
const hasGlobalAccess = await this.hasGlobalPermission(permissionKey);
|
||||
|
||||
// 如果有全局权限,直接允许批量操作
|
||||
// If the user has global permission, allow the batch operation directly
|
||||
if (hasGlobalAccess) {
|
||||
this.log('info', `权限通过:批量操作,当前user拥有 ${permissionKey} ALL权限`);
|
||||
return { isPermitted: true };
|
||||
}
|
||||
|
||||
// 获取所有资源的用户 ID
|
||||
// Get the user IDs for all resources
|
||||
let userIds: string[];
|
||||
try {
|
||||
// 根据 targetInfoIds 中的属性自动判断资源类型
|
||||
// Automatically determine the resource type based on properties in targetInfoIds
|
||||
switch (true) {
|
||||
case !!targetInfoIds.targetSessionIds?.length: {
|
||||
const sessionList = await this.db.query.sessions.findMany({
|
||||
@@ -450,7 +450,7 @@ export abstract class BaseService implements IBaseService {
|
||||
where: and(inArray(aiProviders.id, providerIds), eq(aiProviders.userId, this.userId)),
|
||||
});
|
||||
|
||||
// 先尝试按复合主键 (id, userId) 命中当前用户,避免同 provider id 多用户时误判
|
||||
// First try to match the current user by composite key (id, userId) to avoid false positives when multiple users share the same provider id
|
||||
if (ownedProviders.length === providerIds.length) {
|
||||
userIds = ownedProviders.map(() => this.userId);
|
||||
break;
|
||||
@@ -509,7 +509,7 @@ export abstract class BaseService implements IBaseService {
|
||||
};
|
||||
}
|
||||
|
||||
// 如果找不到任何资源
|
||||
// If no resources are found
|
||||
if (userIds.length === 0) {
|
||||
this.log('warn', '未找到任何目标资源', { permissionKey, targetInfoIds });
|
||||
return {
|
||||
@@ -519,10 +519,10 @@ export abstract class BaseService implements IBaseService {
|
||||
};
|
||||
}
|
||||
|
||||
// 检查是否所有资源都属于当前用户
|
||||
// Check if all resources belong to the current user
|
||||
const allBelongToCurrentUser = userIds.every((id) => id === this.userId);
|
||||
if (allBelongToCurrentUser) {
|
||||
// 检查用户是否有 owner 权限
|
||||
// Check if the user has owner permission
|
||||
const hasOwnerAccess = await this.hasOwnerPermission(permissionKey);
|
||||
|
||||
if (hasOwnerAccess) {
|
||||
@@ -533,7 +533,7 @@ export abstract class BaseService implements IBaseService {
|
||||
return { condition: { userIds }, isPermitted: true };
|
||||
}
|
||||
|
||||
// 如果所有资源都属于当前用户,但用户没有 owner 权限,则不允许操作
|
||||
// If all resources belong to the current user but the user has no owner permission, deny the operation
|
||||
this.log('warn', '权限拒绝:批量操作需要 ${permissionKey} ALL/owner 权限', {
|
||||
permissionKey,
|
||||
targetInfoIds,
|
||||
@@ -545,7 +545,7 @@ export abstract class BaseService implements IBaseService {
|
||||
};
|
||||
}
|
||||
|
||||
// 操作的资源中有不属于当前用户的资源,直接拒绝
|
||||
// Some resources in the operation do not belong to the current user; deny directly
|
||||
this.log('warn', `权限拒绝:批量操作需要 ${permissionKey} ALL/owner 权限`, {
|
||||
permissionKey,
|
||||
targetInfoIds,
|
||||
@@ -559,16 +559,16 @@ export abstract class BaseService implements IBaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户是否拥有聊天相关的所有必要权限
|
||||
* 包括:
|
||||
* - 消息读写权限 (MESSAGE_READ, MESSAGE_WRITE)
|
||||
* - 话题读写权限 (TOPIC_READ, TOPIC_WRITE)
|
||||
* - 会话读写权限 (SESSION_READ, SESSION_WRITE)
|
||||
* - AI 模型读权限 (AI_MODEL_READ)
|
||||
* - 助手读权限 (AGENT_READ)
|
||||
* - 文件读权限 (FILE_READ)
|
||||
* Check if the user has all required chat-related permissions
|
||||
* Including:
|
||||
* - Message read/write permissions (MESSAGE_READ, MESSAGE_WRITE)
|
||||
* - Topic read/write permissions (TOPIC_READ, TOPIC_WRITE)
|
||||
* - Session read/write permissions (SESSION_READ, SESSION_WRITE)
|
||||
* - AI model read permission (AI_MODEL_READ)
|
||||
* - Agent read permission (AGENT_READ)
|
||||
* - File read permission (FILE_READ)
|
||||
*
|
||||
* @returns 返回权限检查结果和缺失的权限列表
|
||||
* @returns Returns the permission check result and list of missing permissions
|
||||
*/
|
||||
protected async resolveChatPermissions(): Promise<{
|
||||
isPermitted: boolean;
|
||||
|
||||
@@ -19,7 +19,7 @@ import type {
|
||||
} from '../types/agent.type';
|
||||
|
||||
/**
|
||||
* Agent 服务实现类
|
||||
* Agent service implementation class
|
||||
*/
|
||||
export class AgentService extends BaseService {
|
||||
constructor(db: LobeChatDatabase, userId: string | null) {
|
||||
@@ -27,10 +27,10 @@ export class AgentService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的 Agent 列表
|
||||
* @param page 页码,从1开始
|
||||
* @param pageSize 每页数量,最大100
|
||||
* @returns 用户的 Agent 列表
|
||||
* Get the user's Agent list
|
||||
* @param page Page number, starting from 1
|
||||
* @param pageSize Items per page, maximum 100
|
||||
* @returns The user's Agent list
|
||||
*/
|
||||
async queryAgents(request: GetAgentsRequest): ServiceResult<AgentListResponse> {
|
||||
this.log('info', '获取 Agent 列表', { request });
|
||||
@@ -38,7 +38,7 @@ export class AgentService extends BaseService {
|
||||
const { keyword } = request;
|
||||
|
||||
try {
|
||||
// 基础过滤条件:当前用户 + 排除虚拟 agent(inbox、supervisor 等)
|
||||
// Base filter: current user + exclude virtual agents (inbox, supervisor, etc.)
|
||||
const baseConditions = and(
|
||||
eq(agents.userId, this.userId),
|
||||
or(eq(agents.virtual, false), isNull(agents.virtual)),
|
||||
@@ -70,16 +70,16 @@ export class AgentService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建智能体
|
||||
* @param request 创建请求参数
|
||||
* @returns 创建完成的 Agent 信息
|
||||
* Create an agent
|
||||
* @param request Create request parameters
|
||||
* @returns Created Agent info
|
||||
*/
|
||||
async createAgent(request: CreateAgentRequest): ServiceResult<AgentDetailResponse> {
|
||||
this.log('info', '创建智能体', { title: request.title });
|
||||
|
||||
try {
|
||||
return await this.db.transaction(async (tx) => {
|
||||
// 准备创建数据
|
||||
// Prepare creation data
|
||||
const newAgentData: NewAgent = {
|
||||
accessedAt: new Date(),
|
||||
avatar: request.avatar || null,
|
||||
@@ -90,14 +90,14 @@ export class AgentService extends BaseService {
|
||||
model: request.model || null,
|
||||
params: request.params ?? {},
|
||||
provider: request.provider || null,
|
||||
slug: randomSlug(4), // 系统自动生成 slug
|
||||
slug: randomSlug(4), // Auto-generated slug
|
||||
systemRole: request.systemRole || null,
|
||||
title: request.title,
|
||||
updatedAt: new Date(),
|
||||
userId: this.userId,
|
||||
};
|
||||
|
||||
// 插入数据库
|
||||
// Insert into database
|
||||
const [createdAgent] = await tx.insert(agents).values(newAgentData).returning();
|
||||
this.log('info', 'Agent 创建成功', { id: createdAgent.id, slug: createdAgent.slug });
|
||||
|
||||
@@ -109,15 +109,15 @@ export class AgentService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新智能体
|
||||
* @param request 更新请求参数
|
||||
* @returns 更新后的 Agent 信息
|
||||
* Update an agent
|
||||
* @param request Update request parameters
|
||||
* @returns Updated Agent info
|
||||
*/
|
||||
async updateAgent(request: UpdateAgentRequest): ServiceResult<AgentDetailResponse> {
|
||||
this.log('info', '更新智能体', { id: request.id, title: request.title });
|
||||
|
||||
try {
|
||||
// 权限校验
|
||||
// Permission validation
|
||||
const permissionResult = await this.resolveOperationPermission('AGENT_UPDATE', {
|
||||
targetAgentId: request.id,
|
||||
});
|
||||
@@ -127,13 +127,13 @@ export class AgentService extends BaseService {
|
||||
}
|
||||
|
||||
return await this.db.transaction(async (tx) => {
|
||||
// 构建查询条件
|
||||
// Build query conditions
|
||||
const whereConditions = [eq(agents.id, request.id)];
|
||||
if (permissionResult.condition?.userId) {
|
||||
whereConditions.push(eq(agents.userId, permissionResult.condition.userId));
|
||||
}
|
||||
|
||||
// 检查 Agent 是否存在
|
||||
// Check if the Agent exists
|
||||
const existingAgent = await tx.query.agents.findFirst({
|
||||
where: and(...whereConditions),
|
||||
});
|
||||
@@ -142,7 +142,7 @@ export class AgentService extends BaseService {
|
||||
throw this.createBusinessError(`Agent ID "${request.id}" 不存在`);
|
||||
}
|
||||
|
||||
// 只更新请求中实际传入的字段,避免用 undefined 覆盖已有值
|
||||
// Only update fields actually provided in the request to avoid overwriting existing values with undefined
|
||||
const updateData: Record<string, unknown> = { updatedAt: new Date() };
|
||||
|
||||
if (request.avatar !== undefined) updateData.avatar = request.avatar ?? null;
|
||||
@@ -153,7 +153,7 @@ export class AgentService extends BaseService {
|
||||
if (request.systemRole !== undefined) updateData.systemRole = request.systemRole ?? null;
|
||||
if (request.title !== undefined) updateData.title = request.title;
|
||||
|
||||
// params 采用合并更新,而非全量覆盖
|
||||
// Merge params instead of fully overwriting
|
||||
if (request.params !== undefined) {
|
||||
const existingParams = (existingAgent.params as Record<string, unknown>) ?? {};
|
||||
const incomingParams = request.params ?? {};
|
||||
@@ -170,7 +170,7 @@ export class AgentService extends BaseService {
|
||||
updateData.params = mergedParams;
|
||||
}
|
||||
|
||||
// 更新数据库
|
||||
// Update database
|
||||
const [updatedAgent] = await tx
|
||||
.update(agents)
|
||||
.set(updateData)
|
||||
@@ -186,8 +186,8 @@ export class AgentService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除智能体
|
||||
* @param request 删除请求参数
|
||||
* Delete an agent
|
||||
* @param request Delete request parameters
|
||||
*/
|
||||
async deleteAgent(request: AgentDeleteRequest): ServiceResult<void> {
|
||||
this.log('info', '删除智能体', {
|
||||
@@ -196,7 +196,7 @@ export class AgentService extends BaseService {
|
||||
});
|
||||
|
||||
try {
|
||||
// 权限校验
|
||||
// Permission validation
|
||||
const permissionResult = await this.resolveOperationPermission('AGENT_DELETE', {
|
||||
targetAgentId: request.agentId,
|
||||
});
|
||||
@@ -205,7 +205,7 @@ export class AgentService extends BaseService {
|
||||
throw this.createAuthorizationError(permissionResult.message || '无权删除此 Agent');
|
||||
}
|
||||
|
||||
// 检查要删除的 Agent 是否存在
|
||||
// Check if the Agent to be deleted exists
|
||||
const targetAgent = await this.db.query.agents.findFirst({
|
||||
where: eq(agents.id, request.agentId),
|
||||
});
|
||||
@@ -215,7 +215,7 @@ export class AgentService extends BaseService {
|
||||
}
|
||||
|
||||
if (request.migrateSessionTo) {
|
||||
// 验证迁移目标 Agent 存在且属于当前用户
|
||||
// Validate that the migration target Agent exists and belongs to the current user
|
||||
const migrateTarget = await this.db.query.agents.findFirst({
|
||||
where: and(eq(agents.id, request.migrateSessionTo), eq(agents.userId, this.userId)),
|
||||
});
|
||||
@@ -224,7 +224,7 @@ export class AgentService extends BaseService {
|
||||
throw this.createBusinessError(`迁移目标 Agent ID ${request.migrateSessionTo} 不存在`);
|
||||
}
|
||||
|
||||
// 迁移会话关联关系到目标 Agent
|
||||
// Migrate session associations to the target Agent
|
||||
await this.migrateAgentSessions(request.agentId, request.migrateSessionTo);
|
||||
|
||||
this.log('info', '会话迁移完成', {
|
||||
@@ -232,12 +232,12 @@ export class AgentService extends BaseService {
|
||||
to: request.migrateSessionTo,
|
||||
});
|
||||
|
||||
// 迁移完成后直接删除 agent 本身,sessions 已转移不需要级联删除
|
||||
// After migration, delete the agent itself directly; sessions have been transferred so cascade delete is not needed
|
||||
await this.db
|
||||
.delete(agents)
|
||||
.where(and(eq(agents.id, request.agentId), eq(agents.userId, this.userId)));
|
||||
} else {
|
||||
// 无迁移:复用 AgentModel.delete,会级联删除关联的 sessions、messages、topics 等
|
||||
// No migration: reuse AgentModel.delete, which cascades deletion of associated sessions, messages, topics, etc.
|
||||
const agentModel = new AgentModel(this.db, this.userId);
|
||||
await agentModel.delete(request.agentId);
|
||||
}
|
||||
@@ -249,15 +249,15 @@ export class AgentService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 ID 获取 Agent 详情
|
||||
* Get Agent details by ID
|
||||
* @param agentId Agent ID
|
||||
* @returns Agent 详情
|
||||
* @returns Agent details
|
||||
*/
|
||||
async getAgentById(agentId: string): ServiceResult<AgentDetailResponse | null> {
|
||||
this.log('info', '根据 ID 获取 Agent 详情', { agentId });
|
||||
|
||||
try {
|
||||
// 权限校验
|
||||
// Permission validation
|
||||
const permissionResult = await this.resolveOperationPermission('AGENT_READ', {
|
||||
targetAgentId: agentId,
|
||||
});
|
||||
@@ -270,7 +270,7 @@ export class AgentService extends BaseService {
|
||||
throw this.createAuthError('未登录,无法获取 Agent 详情');
|
||||
}
|
||||
|
||||
// 复用 AgentModel 的方法获取完整的 Agent 配置
|
||||
// Reuse AgentModel methods to get the full Agent configuration
|
||||
const agentModel = new AgentModel(this.db, this.userId);
|
||||
const agent = await agentModel.getAgentConfigById(agentId);
|
||||
|
||||
@@ -286,9 +286,9 @@ export class AgentService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 迁移 Agent 的会话到另一个 Agent
|
||||
* @param fromAgentId 源 Agent ID
|
||||
* @param toAgentId 目标 Agent ID
|
||||
* Migrate an Agent's sessions to another Agent
|
||||
* @param fromAgentId Source Agent ID
|
||||
* @param toAgentId Target Agent ID
|
||||
* @private
|
||||
*/
|
||||
private async migrateAgentSessions(fromAgentId: string, toAgentId: string): Promise<void> {
|
||||
@@ -296,7 +296,7 @@ export class AgentService extends BaseService {
|
||||
|
||||
try {
|
||||
await this.db.transaction(async (tx) => {
|
||||
// 获取源 Agent 关联的所有 sessionId
|
||||
// Get all sessionIds associated with the source Agent
|
||||
const links = await tx
|
||||
.select({ sessionId: agentsToSessions.sessionId })
|
||||
.from(agentsToSessions)
|
||||
@@ -311,8 +311,8 @@ export class AgentService extends BaseService {
|
||||
|
||||
const sessionIds = links.map((l) => l.sessionId);
|
||||
|
||||
// 删除源 agent 的关联记录,再插入指向目标 agent 的关联记录
|
||||
// 直接 update agentId 可能违反 unique 约束,所以用 delete + insert
|
||||
// Delete source agent's association records, then insert new records pointing to the target agent
|
||||
// Directly updating agentId may violate the unique constraint, so use delete + insert instead
|
||||
await tx
|
||||
.delete(agentsToSessions)
|
||||
.where(
|
||||
@@ -322,7 +322,7 @@ export class AgentService extends BaseService {
|
||||
),
|
||||
);
|
||||
|
||||
// 检查目标 agent 是否已与这些 session 关联,避免重复插入
|
||||
// Check if the target agent is already associated with these sessions to avoid duplicate inserts
|
||||
const existingLinks = await tx
|
||||
.select({ sessionId: agentsToSessions.sessionId })
|
||||
.from(agentsToSessions)
|
||||
|
||||
@@ -15,8 +15,8 @@ import type {
|
||||
} from '../types/model.type';
|
||||
|
||||
/**
|
||||
* 模型服务实现类 (Hono API 专用)
|
||||
* 提供模型的查询和分组功能
|
||||
* Model service implementation class (dedicated to Hono API)
|
||||
* Provides model query and grouping functionality
|
||||
*/
|
||||
export class ModelService extends BaseService {
|
||||
constructor(db: LobeChatDatabase, userId: string | null) {
|
||||
@@ -24,8 +24,8 @@ export class ModelService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模型列表
|
||||
* @param request 查询请求参数
|
||||
* Get model list
|
||||
* @param request Query request parameters
|
||||
*/
|
||||
async getModels(request: ModelsListQuery = {}): ServiceResult<GetModelsResponse> {
|
||||
this.log('info', '获取模型列表', {
|
||||
@@ -34,25 +34,25 @@ export class ModelService extends BaseService {
|
||||
});
|
||||
|
||||
try {
|
||||
// 权限校验
|
||||
// Permission validation
|
||||
const permissionResult = await this.resolveOperationPermission('AI_MODEL_READ');
|
||||
|
||||
if (!permissionResult.isPermitted) {
|
||||
throw this.createAuthorizationError(permissionResult.message || '无权访问模型列表');
|
||||
}
|
||||
|
||||
// 构建查询条件
|
||||
// Build query conditions
|
||||
const conditions = [];
|
||||
|
||||
// 权限条件直接加入主条件数组
|
||||
// Add permission condition directly to the main conditions array
|
||||
if (permissionResult.condition?.userId) {
|
||||
conditions.push(eq(aiModels.userId, permissionResult.condition.userId));
|
||||
}
|
||||
|
||||
// 处理 ModelsListQuery 特定参数
|
||||
// Handle ModelsListQuery-specific parameters
|
||||
const { page, pageSize, keyword, provider, type, enabled } = request;
|
||||
|
||||
// 如果提供了关键词,添加到查询条件中
|
||||
// If a keyword is provided, add it to the query conditions
|
||||
if (keyword) {
|
||||
conditions.push(
|
||||
or(
|
||||
@@ -77,10 +77,10 @@ export class ModelService extends BaseService {
|
||||
|
||||
const finalWhereCondition = conditions.length > 0 ? and(...conditions) : undefined;
|
||||
|
||||
// 计算偏移量
|
||||
// Calculate offset
|
||||
const { limit, offset } = processPaginationConditions({ page, pageSize });
|
||||
|
||||
// 并行执行查询和计数
|
||||
// Execute query and count in parallel
|
||||
const [result, totalResult] = await Promise.all([
|
||||
this.db.query.aiModels.findMany({
|
||||
limit,
|
||||
@@ -101,7 +101,7 @@ export class ModelService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模型详情
|
||||
* Get model details
|
||||
*/
|
||||
async getModelDetail(providerId: string, modelId: string): ServiceResult<ModelDetailResponse> {
|
||||
this.log('info', '获取模型详情', { modelId, providerId, userId: this.userId });
|
||||
@@ -134,7 +134,7 @@ export class ModelService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建模型
|
||||
* Create a model
|
||||
*/
|
||||
async createModel(payload: CreateModelRequest): ServiceResult<ModelDetailResponse> {
|
||||
this.log('info', '创建模型', { payload, userId: this.userId });
|
||||
@@ -192,7 +192,7 @@ export class ModelService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新模型
|
||||
* Update a model
|
||||
*/
|
||||
async updateModel(
|
||||
providerId: string,
|
||||
|
||||
@@ -29,7 +29,7 @@ export class RoleService extends BaseService {
|
||||
*/
|
||||
async getRoles(request: RolesListQuery): ServiceResult<RolesListResponse> {
|
||||
try {
|
||||
// 权限检查
|
||||
// Permission check
|
||||
const permissionResult = await this.resolveOperationPermission('RBAC_ROLE_READ');
|
||||
if (!permissionResult.isPermitted) {
|
||||
throw this.createAuthorizationError(permissionResult.message || '无权访问角色列表');
|
||||
@@ -82,7 +82,7 @@ export class RoleService extends BaseService {
|
||||
* @returns Promise<RoleItem[]> - Array of active roles
|
||||
*/
|
||||
async getActiveRoles(): ServiceResult<RoleItem[]> {
|
||||
// 权限检查
|
||||
// Permission check
|
||||
const permissionResult = await this.resolveOperationPermission('RBAC_ROLE_READ');
|
||||
if (!permissionResult.isPermitted) {
|
||||
throw this.createAuthorizationError(permissionResult.message || '无权访问活跃角色列表');
|
||||
@@ -104,7 +104,7 @@ export class RoleService extends BaseService {
|
||||
* @returns Promise<RoleItem | undefined> - Role item or undefined if not found
|
||||
*/
|
||||
async getRoleById(id: string): ServiceResult<RoleItem | null> {
|
||||
// 权限检查
|
||||
// Permission check
|
||||
const permissionResult = await this.resolveOperationPermission('RBAC_ROLE_READ');
|
||||
if (!permissionResult.isPermitted) {
|
||||
throw this.createAuthorizationError(permissionResult.message || '无权访问此角色');
|
||||
@@ -126,7 +126,7 @@ export class RoleService extends BaseService {
|
||||
* @returns Promise<RoleItem | undefined> - Role item or undefined if not found
|
||||
*/
|
||||
async getRoleByName(name: string): ServiceResult<RoleItem | null> {
|
||||
// 权限检查
|
||||
// Permission check
|
||||
const permissionResult = await this.resolveOperationPermission('RBAC_ROLE_READ');
|
||||
if (!permissionResult.isPermitted) {
|
||||
throw this.createAuthorizationError(permissionResult.message || '无权访问此角色');
|
||||
@@ -191,7 +191,7 @@ export class RoleService extends BaseService {
|
||||
request: RolePermissionsListRequest,
|
||||
): ServiceResult<RolePermissionsListResponse> {
|
||||
try {
|
||||
// 权限检查
|
||||
// Permission check
|
||||
const permissionResult = await this.resolveOperationPermission('RBAC_PERMISSION_READ');
|
||||
if (!permissionResult.isPermitted) {
|
||||
throw this.createAuthorizationError(permissionResult.message || '无权访问角色权限');
|
||||
@@ -213,7 +213,7 @@ export class RoleService extends BaseService {
|
||||
|
||||
const { limit, offset } = processPaginationConditions(request);
|
||||
|
||||
// 构建列表查询基础
|
||||
// Build the base list query
|
||||
const baseListQuery = this.db
|
||||
.select({
|
||||
category: permissions.category,
|
||||
@@ -229,7 +229,7 @@ export class RoleService extends BaseService {
|
||||
|
||||
const listQuery = limit ? baseListQuery.limit(limit).offset(offset!) : baseListQuery;
|
||||
|
||||
// 构建计数查询
|
||||
// Build the count query
|
||||
const countQuery = this.db
|
||||
.select({ count: count() })
|
||||
.from(permissions)
|
||||
@@ -267,7 +267,7 @@ export class RoleService extends BaseService {
|
||||
const grantSet = new Set(rawGrantIds.filter((id) => typeof id === 'string' && !!id.trim()));
|
||||
const revokeSet = new Set(rawRevokeIds.filter((id) => typeof id === 'string' && !!id.trim()));
|
||||
|
||||
// 解决grant和revoke的交集,交集的权限操作相抵,实际上等于没有操作
|
||||
// Resolve the intersection of grant and revoke sets; intersecting permissions cancel out, effectively resulting in no operation
|
||||
const intersection = new Set<string>();
|
||||
grantSet.forEach((id) => {
|
||||
if (revokeSet.has(id)) {
|
||||
@@ -365,7 +365,7 @@ export class RoleService extends BaseService {
|
||||
async updateRole(id: string, updateData: UpdateRoleRequest): ServiceResult<RoleItem> {
|
||||
this.log('info', '更新角色信息', { roleId: id, updateData });
|
||||
|
||||
// 权限检查
|
||||
// Permission check
|
||||
const permissionResult = await this.resolveOperationPermission('RBAC_ROLE_UPDATE');
|
||||
if (!permissionResult.isPermitted) {
|
||||
throw this.createAuthorizationError(permissionResult.message || '无权更新角色');
|
||||
@@ -373,7 +373,7 @@ export class RoleService extends BaseService {
|
||||
|
||||
try {
|
||||
return await this.db.transaction(async (tx) => {
|
||||
// 检查角色是否存在
|
||||
// Check if the role exists
|
||||
const existingRole = await tx.query.roles.findFirst({
|
||||
where: eq(roles.id, id),
|
||||
});
|
||||
@@ -382,12 +382,12 @@ export class RoleService extends BaseService {
|
||||
throw this.createNotFoundError(`角色 ID "${id}" 不存在`);
|
||||
}
|
||||
|
||||
// 检查是否为系统角色,系统角色不允许修改某些字段
|
||||
// Check if it is a system role; system roles cannot have certain fields modified
|
||||
if (existingRole.isSystem && (updateData.name || updateData.isSystem === false)) {
|
||||
throw this.createBusinessError('系统角色不允许修改名称或系统属性');
|
||||
}
|
||||
|
||||
// 如果要修改角色名称,检查新名称是否已存在
|
||||
// If the role name is being modified, check whether the new name already exists
|
||||
if (updateData.name && updateData.name !== existingRole.name) {
|
||||
const duplicateRole = await tx.query.roles.findFirst({
|
||||
where: eq(roles.name, updateData.name),
|
||||
@@ -398,7 +398,7 @@ export class RoleService extends BaseService {
|
||||
}
|
||||
}
|
||||
|
||||
// 准备更新数据
|
||||
// Prepare update fields
|
||||
const updateFields = {
|
||||
...(updateData.name !== undefined && { name: updateData.name }),
|
||||
...(updateData.displayName !== undefined && { displayName: updateData.displayName }),
|
||||
@@ -408,7 +408,7 @@ export class RoleService extends BaseService {
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
// 执行更新
|
||||
// Execute the update
|
||||
const [updatedRole] = await tx
|
||||
.update(roles)
|
||||
.set(updateFields)
|
||||
@@ -429,20 +429,20 @@ export class RoleService extends BaseService {
|
||||
async clearRolePermissions(roleId: string): ServiceResult<{ removed: number; roleId: string }> {
|
||||
this.log('info', '清空角色权限', { roleId });
|
||||
|
||||
// 权限检查
|
||||
// Permission check
|
||||
const permissionResult = await this.resolveOperationPermission('RBAC_ROLE_UPDATE');
|
||||
if (!permissionResult.isPermitted) {
|
||||
throw this.createAuthorizationError(permissionResult.message || '无权清空角色权限');
|
||||
}
|
||||
|
||||
try {
|
||||
// 检查角色是否存在
|
||||
// Check if the role exists
|
||||
const existingRole = await this.db.query.roles.findFirst({ where: eq(roles.id, roleId) });
|
||||
if (!existingRole) {
|
||||
throw this.createNotFoundError(`角色 ID "${roleId}" 不存在`);
|
||||
}
|
||||
|
||||
// 统计并删除
|
||||
// Count and delete
|
||||
const before = await this.db
|
||||
.select({ count: sql<number>`count(*)` })
|
||||
.from(rolePermissions)
|
||||
|
||||
@@ -21,7 +21,7 @@ import type {
|
||||
} from '../types/user.type';
|
||||
|
||||
/**
|
||||
* 用户服务实现类
|
||||
* User service implementation class
|
||||
*/
|
||||
export class UserService extends BaseService {
|
||||
constructor(db: LobeChatDatabase, userId: string | null) {
|
||||
@@ -29,12 +29,12 @@ export class UserService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息和角色信息
|
||||
* @param userId 用户ID
|
||||
* @returns 用户信息和角色信息
|
||||
* Get user info and role info
|
||||
* @param userId User ID
|
||||
* @returns User info and role info
|
||||
*/
|
||||
private async getUserWithRoles(userId: string): Promise<UserWithRoles> {
|
||||
// 使用子查询的方式避免复杂的GROUP BY
|
||||
// Use subquery approach to avoid complex GROUP BY
|
||||
const user = await this.db.query.users.findFirst({
|
||||
where: eq(users.id, userId),
|
||||
});
|
||||
@@ -43,7 +43,7 @@ export class UserService extends BaseService {
|
||||
throw this.createNotFoundError('用户不存在');
|
||||
}
|
||||
|
||||
// 并行获取角色和消息数量,提高效率
|
||||
// Fetch roles and message count in parallel for better efficiency
|
||||
const [userRoleResults, messageCountResult] = await Promise.all([
|
||||
this.db
|
||||
.select({ roles })
|
||||
@@ -62,39 +62,39 @@ export class UserService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
* @returns 用户信息
|
||||
* Get the currently logged-in user info
|
||||
* @returns User info
|
||||
*/
|
||||
async getCurrentUser(): ServiceResult<UserWithRoles> {
|
||||
this.log('info', '获取当前登录用户信息及角色信息');
|
||||
|
||||
// 查询用户基本信息
|
||||
// Query basic user info
|
||||
return this.getUserWithRoles(this.userId!);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统中所有用户列表(分页)
|
||||
* @returns 用户列表(包含角色信息和消息数量)
|
||||
* Get a paginated list of all users in the system
|
||||
* @returns User list (including role info and message count)
|
||||
*/
|
||||
async queryUsers(request: UserListRequest): ServiceResult<UserListResponse> {
|
||||
this.log('info', '获取系统中所有用户列表');
|
||||
|
||||
try {
|
||||
// 权限校验
|
||||
// Permission validation
|
||||
const permissionResult = await this.resolveOperationPermission('USER_READ', ALL_SCOPE);
|
||||
|
||||
if (!permissionResult.isPermitted) {
|
||||
throw this.createAuthorizationError(permissionResult.message || '没有权限查看用户列表');
|
||||
}
|
||||
|
||||
// 构建查询条件
|
||||
// Build query conditions
|
||||
const conditions = [];
|
||||
|
||||
if (request.keyword) {
|
||||
conditions.push(ilike(users.fullName, `%${request.keyword}%`));
|
||||
}
|
||||
|
||||
// 获取用户基本信息
|
||||
// Get basic user info
|
||||
const query = this.db.query.users.findMany({
|
||||
...processPaginationConditions(request),
|
||||
orderBy: desc(users.createdAt),
|
||||
@@ -108,7 +108,7 @@ export class UserService extends BaseService {
|
||||
|
||||
const [userList, countResult] = await Promise.all([query, countQuery]);
|
||||
|
||||
// 为每个用户获取角色和消息数量
|
||||
// Fetch roles and message count for each user
|
||||
const usersWithRoles = await Promise.all(
|
||||
userList.map(async (userRow) => {
|
||||
const userRoleResults = await this.db
|
||||
@@ -142,15 +142,15 @@ export class UserService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新用户
|
||||
* @param userData 用户创建数据
|
||||
* @returns 创建的用户信息(包含角色信息)
|
||||
* Create a new user
|
||||
* @param userData User creation data
|
||||
* @returns Created user info (including role info)
|
||||
*/
|
||||
async createUser(userData: CreateUserRequest): ServiceResult<UserWithRoles> {
|
||||
this.log('info', '创建新用户', { userData });
|
||||
|
||||
try {
|
||||
// 权限校验
|
||||
// Permission validation
|
||||
const permissionResult = await this.resolveOperationPermission('USER_CREATE');
|
||||
|
||||
if (!permissionResult.isPermitted) {
|
||||
@@ -159,7 +159,7 @@ export class UserService extends BaseService {
|
||||
|
||||
const { roleIds, ...rest } = userData;
|
||||
|
||||
// 检查用户名、邮箱和ID是否已存在
|
||||
// Check if the username, email, and ID already exist
|
||||
const conditions = [];
|
||||
|
||||
if (rest.username) {
|
||||
@@ -193,10 +193,10 @@ export class UserService extends BaseService {
|
||||
}
|
||||
}
|
||||
|
||||
// 使用用户指定的ID或生成新的ID
|
||||
// Use the user-specified ID or generate a new one
|
||||
const userId = rest.id || idGenerator('user');
|
||||
|
||||
// 插入新用户,Id使用用户指定的ID或生成新的ID
|
||||
// Insert new user; ID uses the user-specified ID or a generated one
|
||||
const [createdUser] = await this.db
|
||||
.insert(users)
|
||||
.values({
|
||||
@@ -205,7 +205,7 @@ export class UserService extends BaseService {
|
||||
})
|
||||
.returning();
|
||||
|
||||
// 插入用户角色
|
||||
// Insert user roles
|
||||
if (roleIds && roleIds.length > 0) {
|
||||
const rbacModel = new RbacModel(this.db, userId);
|
||||
await rbacModel.updateUserRoles(userId, roleIds);
|
||||
@@ -213,7 +213,7 @@ export class UserService extends BaseService {
|
||||
|
||||
this.log('info', '用户创建成功', { userId: createdUser.id });
|
||||
|
||||
// 返回包含角色信息的用户数据
|
||||
// Return user data including role info
|
||||
return this.getUserWithRoles(userId);
|
||||
} catch (error) {
|
||||
return this.handleServiceError(error, '创建用户');
|
||||
@@ -221,16 +221,16 @@ export class UserService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户信息
|
||||
* @param userId 用户ID
|
||||
* @param userData 更新数据
|
||||
* @returns 更新后的用户信息(包含角色信息)
|
||||
* Update user info
|
||||
* @param userId User ID
|
||||
* @param userData Update data
|
||||
* @returns Updated user info (including role info)
|
||||
*/
|
||||
async updateUser(userId: string, userData: UpdateUserRequest): ServiceResult<UserWithRoles> {
|
||||
this.log('info', '更新用户信息', { userData, userId });
|
||||
|
||||
try {
|
||||
// 权限校验
|
||||
// Permission validation
|
||||
const permissionResult = await this.resolveOperationPermission('USER_UPDATE', {
|
||||
targetUserId: userId,
|
||||
});
|
||||
@@ -241,7 +241,7 @@ export class UserService extends BaseService {
|
||||
|
||||
const { roleIds, ...rest } = userData;
|
||||
|
||||
// 检查用户是否存在
|
||||
// Check if the user exists
|
||||
const existingUser = await this.db.query.users.findFirst({
|
||||
where: eq(users.id, userId),
|
||||
});
|
||||
@@ -250,7 +250,7 @@ export class UserService extends BaseService {
|
||||
throw this.createNotFoundError('用户不存在');
|
||||
}
|
||||
|
||||
// 检查用户名和邮箱是否被其他用户使用
|
||||
// Check if the username or email is already used by another user
|
||||
if (rest.username && rest.username !== existingUser.username) {
|
||||
const existingUserByUsername = await this.db.query.users.findFirst({
|
||||
where: and(eq(users.username, rest.username), ne(users.id, userId)),
|
||||
@@ -275,7 +275,7 @@ export class UserService extends BaseService {
|
||||
await rbacModel.updateUserRoles(userId, roleIds);
|
||||
}
|
||||
|
||||
// 更新用户信息
|
||||
// Update user info
|
||||
await this.db
|
||||
.update(users)
|
||||
.set({
|
||||
@@ -293,15 +293,15 @@ export class UserService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除用户
|
||||
* @param userId 用户ID
|
||||
* @returns 删除操作结果
|
||||
* Delete a user
|
||||
* @param userId User ID
|
||||
* @returns Delete operation result
|
||||
*/
|
||||
async deleteUser(userId: string): ServiceResult<{ id: string }> {
|
||||
this.log('info', '删除用户', { userId });
|
||||
|
||||
try {
|
||||
// 权限校验
|
||||
// Permission validation
|
||||
const permissionResult = await this.resolveOperationPermission('USER_DELETE', {
|
||||
targetUserId: userId,
|
||||
});
|
||||
@@ -310,7 +310,7 @@ export class UserService extends BaseService {
|
||||
throw this.createAuthorizationError(permissionResult.message || '没有权限删除该用户');
|
||||
}
|
||||
|
||||
// 检查用户是否存在
|
||||
// Check if the user exists
|
||||
const result = await this.db.delete(users).where(eq(users.id, userId));
|
||||
|
||||
if (!result.rowCount) {
|
||||
@@ -326,15 +326,15 @@ export class UserService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据ID获取用户信息
|
||||
* @param userId 用户ID
|
||||
* @returns 用户信息(包含角色信息和消息数量)
|
||||
* Get user info by ID
|
||||
* @param userId User ID
|
||||
* @returns User info (including role info and message count)
|
||||
*/
|
||||
async getUserById(userId: string): ServiceResult<UserWithRoles> {
|
||||
this.log('info', '根据ID获取用户信息', { userId });
|
||||
|
||||
try {
|
||||
// 权限校验
|
||||
// Permission validation
|
||||
const permissionResult = await this.resolveOperationPermission('USER_READ', {
|
||||
targetUserId: userId,
|
||||
});
|
||||
@@ -343,7 +343,7 @@ export class UserService extends BaseService {
|
||||
throw this.createAuthorizationError(permissionResult.message || '没有权限查看该用户信息');
|
||||
}
|
||||
|
||||
// 查询用户基本信息
|
||||
// Query basic user info
|
||||
return this.getUserWithRoles(userId);
|
||||
} catch (error) {
|
||||
return this.handleServiceError(error, '获取用户信息');
|
||||
@@ -351,10 +351,10 @@ export class UserService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户角色
|
||||
* @param userId 目标用户ID
|
||||
* @param request 更新角色请求
|
||||
* @returns 操作结果和最新的用户角色信息
|
||||
* Update user roles
|
||||
* @param userId Target user ID
|
||||
* @param request Update roles request
|
||||
* @returns Operation result and latest user role info
|
||||
*/
|
||||
async updateUserRoles(
|
||||
userId: string,
|
||||
@@ -367,7 +367,7 @@ export class UserService extends BaseService {
|
||||
userId,
|
||||
});
|
||||
|
||||
// 权限校验
|
||||
// Permission validation
|
||||
const permissionResult = await this.resolveOperationPermission('RBAC_USER_ROLE_UPDATE', {
|
||||
targetUserId: userId,
|
||||
});
|
||||
@@ -377,7 +377,7 @@ export class UserService extends BaseService {
|
||||
}
|
||||
|
||||
return await this.db.transaction(async (tx) => {
|
||||
// 1. 验证目标用户存在
|
||||
// 1. Validate that the target user exists
|
||||
const targetUser = await tx.query.users.findFirst({
|
||||
where: eq(users.id, userId),
|
||||
});
|
||||
@@ -386,12 +386,12 @@ export class UserService extends BaseService {
|
||||
throw this.createNotFoundError(`用户 ${userId} 不存在`);
|
||||
}
|
||||
|
||||
// 2. 收集所有需要验证的角色ID
|
||||
// 2. Collect all role IDs that need to be validated
|
||||
const allRoleIds = new Set<string>();
|
||||
request.addRoles?.forEach((role) => allRoleIds.add(role.roleId));
|
||||
request.removeRoles?.forEach((roleId) => allRoleIds.add(roleId));
|
||||
|
||||
// 3. 验证所有角色存在且激活
|
||||
// 3. Validate that all roles exist and are active
|
||||
if (allRoleIds.size > 0) {
|
||||
const existingRoles = await tx.query.roles.findMany({
|
||||
where: and(inArray(roles.id, Array.from(allRoleIds)), eq(roles.isActive, true)),
|
||||
@@ -411,7 +411,7 @@ export class UserService extends BaseService {
|
||||
removed: 0,
|
||||
};
|
||||
|
||||
// 5. 处理移除角色
|
||||
// 5. Handle role removal
|
||||
if (request.removeRoles && request.removeRoles.length > 0) {
|
||||
await tx
|
||||
.delete(userRoles)
|
||||
@@ -422,7 +422,7 @@ export class UserService extends BaseService {
|
||||
this.log('info', '移除用户角色成功');
|
||||
}
|
||||
|
||||
// 6. 处理添加角色
|
||||
// 6. Handle role addition
|
||||
if (request.addRoles && request.addRoles.length > 0) {
|
||||
const insertData = request.addRoles.map((role) => {
|
||||
const data = {
|
||||
@@ -437,7 +437,7 @@ export class UserService extends BaseService {
|
||||
await tx.insert(userRoles).values(insertData).onConflictDoNothing().returning();
|
||||
}
|
||||
|
||||
// 7. 获取更新后的用户角色信息
|
||||
// 7. Get the updated user role info
|
||||
const userWithRoles = await tx
|
||||
.select({ role: roles, userRole: userRoles })
|
||||
.from(userRoles)
|
||||
@@ -464,15 +464,15 @@ export class UserService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户的角色信息
|
||||
* @param userId 用户ID
|
||||
* @returns 用户角色详情
|
||||
* Get user role info
|
||||
* @param userId User ID
|
||||
* @returns User role details
|
||||
*/
|
||||
async getUserRoles(userId: string): ServiceResult<UserRolesResponse> {
|
||||
this.log('info', '获取用户角色信息', { userId });
|
||||
|
||||
try {
|
||||
// 权限校验
|
||||
// Permission validation
|
||||
const permissionResult = await this.resolveOperationPermission('USER_READ', {
|
||||
targetUserId: userId,
|
||||
});
|
||||
@@ -481,7 +481,7 @@ export class UserService extends BaseService {
|
||||
throw this.createAuthorizationError(permissionResult.message || '没有权限查看用户角色');
|
||||
}
|
||||
|
||||
// 先检查用户是否存在
|
||||
// First check if the user exists
|
||||
const user = await this.db.query.users.findFirst({
|
||||
where: eq(users.id, userId),
|
||||
});
|
||||
@@ -490,7 +490,7 @@ export class UserService extends BaseService {
|
||||
throw this.createNotFoundError(`用户 ID "${userId}" 不存在`);
|
||||
}
|
||||
|
||||
// 获取用户的角色信息
|
||||
// Get user role info
|
||||
const results = await this.db
|
||||
.select({ role: roles, userRole: userRoles })
|
||||
.from(userRoles)
|
||||
@@ -509,13 +509,13 @@ export class UserService extends BaseService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空用户的角色列表
|
||||
* Clear all roles for a user
|
||||
*/
|
||||
async clearUserRoles(userId: string): ServiceResult<{ removed: number; userId: string }> {
|
||||
this.log('info', '清空用户角色', { userId });
|
||||
|
||||
try {
|
||||
// 权限校验
|
||||
// Permission validation
|
||||
const permissionResult = await this.resolveOperationPermission('RBAC_USER_ROLE_UPDATE', {
|
||||
targetUserId: userId,
|
||||
});
|
||||
@@ -524,13 +524,13 @@ export class UserService extends BaseService {
|
||||
throw this.createAuthorizationError(permissionResult.message || '没有权限清空用户角色');
|
||||
}
|
||||
|
||||
// 检查用户是否存在
|
||||
// Check if the user exists
|
||||
const exist = await this.db.query.users.findFirst({ where: eq(users.id, userId) });
|
||||
if (!exist) {
|
||||
throw this.createNotFoundError(`用户 ${userId} 不存在`);
|
||||
}
|
||||
|
||||
// 统计并删除
|
||||
// Count and delete
|
||||
const beforeCount = await this.db
|
||||
.select({ count: count() })
|
||||
.from(userRoles)
|
||||
|
||||
@@ -2,13 +2,13 @@ import type { PERMISSION_ACTIONS, PermissionScope } from '@/const/rbac';
|
||||
import { getAllowedScopesForAction, RBAC_PERMISSIONS } from '@/const/rbac';
|
||||
|
||||
/**
|
||||
* 获取指定权限的所有scope权限值数组
|
||||
* 直接从预编译的 RBAC_PERMISSIONS 中提取权限码
|
||||
* @param key 权限动作键名
|
||||
* @returns 权限值数组
|
||||
* Get all scope permission value arrays for a given permission
|
||||
* Extracts permission codes directly from the precompiled RBAC_PERMISSIONS
|
||||
* @param key Permission action key name
|
||||
* @returns Array of permission values
|
||||
*/
|
||||
export function getAllScopePermissions(key: keyof typeof PERMISSION_ACTIONS): string[] {
|
||||
// 获取允许的scope,有些资源只有all/workspace权限级别的scope
|
||||
// Get allowed scopes; some resources only have all/workspace scope levels
|
||||
const allowed = getAllowedScopesForAction(key);
|
||||
|
||||
return allowed
|
||||
@@ -20,20 +20,20 @@ export function getAllScopePermissions(key: keyof typeof PERMISSION_ACTIONS): st
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定权限的特定scope权限值数组
|
||||
* 直接从预编译的 RBAC_PERMISSIONS 中提取权限码
|
||||
* @param key 权限动作键名
|
||||
* @param scopes 需要的scope数组
|
||||
* @returns 权限值数组
|
||||
* Get specific scope permission value arrays for a given permission
|
||||
* Extracts permission codes directly from the precompiled RBAC_PERMISSIONS
|
||||
* @param key Permission action key name
|
||||
* @param scopes Array of required scopes
|
||||
* @returns Array of permission values
|
||||
*/
|
||||
export function getScopePermissions(
|
||||
key: keyof typeof PERMISSION_ACTIONS,
|
||||
scopes: PermissionScope[],
|
||||
): string[] {
|
||||
// 获取允许的scope,有些资源只有all/workspace权限级别的scope
|
||||
// Get allowed scopes; some resources only have all/workspace scope levels
|
||||
const allowed = new Set(getAllowedScopesForAction(key));
|
||||
|
||||
// 过滤掉不允许的scope
|
||||
// Filter out disallowed scopes
|
||||
return scopes
|
||||
.filter((scope) => allowed.has(scope))
|
||||
.map((scope) => {
|
||||
|
||||
Reference in New Issue
Block a user