🌐 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:
LobeHub Bot
2026-03-15 11:57:00 +08:00
committed by GitHub
parent 6a4d6c6a86
commit cb955048f3
6 changed files with 222 additions and 222 deletions

View File

@@ -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;

View File

@@ -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 {
// 基础过滤条件:当前用户 + 排除虚拟 agentinboxsupervisor 等)
// 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会级联删除关联的 sessionsmessagestopics
// 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)

View File

@@ -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,

View File

@@ -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)

View File

@@ -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)

View File

@@ -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) => {