diff --git a/routes/bot_manager.py b/routes/bot_manager.py index 46947d2..4c38dc6 100644 --- a/routes/bot_manager.py +++ b/routes/bot_manager.py @@ -1314,87 +1314,47 @@ async def get_bots(authorization: Optional[str] = Header(None)): detail="Unauthorized" ) - # 检查是否是管理员 pool = get_db_pool_manager().pool + async with pool.connection() as conn: async with conn.cursor() as cursor: + # 所有用户(包括 admin)只能看到拥有的 Bot 和分享给自己的 Bot(且未过期) await cursor.execute(""" - SELECT is_admin FROM agent_user WHERE id = %s - """, (user_id,)) - row = await cursor.fetchone() - is_admin = row and row[0] + SELECT DISTINCT b.id, b.name, b.bot_id, b.created_at, b.updated_at, b.settings, + u.id as owner_id, u.username as owner_username, + s.role, s.shared_at, s.expires_at, + b.is_published, b.copied_from + FROM agent_bots b + LEFT JOIN agent_user u ON b.owner_id = u.id + LEFT JOIN bot_shares s ON b.id = s.bot_id AND s.user_id = %s + WHERE b.owner_id = %s + OR (s.user_id IS NOT NULL + AND s.user_id = %s + AND (s.expires_at IS NULL OR s.expires_at > NOW())) + ORDER BY b.created_at DESC + """, (user_id, user_id, user_id)) + rows = await cursor.fetchall() - async with pool.connection() as conn: - async with conn.cursor() as cursor: - if is_admin: - # 管理员可以看到所有 Bot - await cursor.execute(""" - SELECT b.id, b.name, b.bot_id, b.created_at, b.updated_at, b.settings, - u.id as owner_id, u.username as owner_username, - b.is_published, b.copied_from - FROM agent_bots b - LEFT JOIN agent_user u ON b.owner_id = u.id - ORDER BY b.created_at DESC - """) - rows = await cursor.fetchall() - - return [ - BotResponse( - id=str(row[0]), # 使用 UUID 主键 - name=row[1], - bot_id=str(row[0]), # bot_id 也指向主键 id - is_owner=True, - is_shared=False, - is_published=row[8] if row[8] else False, - copied_from=str(row[9]) if row[9] else None, - owner={"id": str(row[6]), "username": row[7]} if row[6] else None, - role=None, - description=row[5].get('description') if row[5] else None, - avatar_url=row[5].get('avatar_url') if row[5] else None, - created_at=datetime_to_str(row[3]), - updated_at=datetime_to_str(row[4]) - ) - for row in rows - ] - else: - # 用户只能看到拥有的 Bot 和分享给自己的 Bot(且未过期) - # 使用子查询确保正确过滤,避免 LEFT JOIN 导致的 NULL 值比较问题 - await cursor.execute(""" - SELECT DISTINCT b.id, b.name, b.bot_id, b.created_at, b.updated_at, b.settings, - u.id as owner_id, u.username as owner_username, - s.role, s.shared_at, s.expires_at, - b.is_published, b.copied_from - FROM agent_bots b - LEFT JOIN agent_user u ON b.owner_id = u.id - LEFT JOIN bot_shares s ON b.id = s.bot_id AND s.user_id = %s - WHERE b.owner_id = %s - OR (s.user_id IS NOT NULL - AND s.user_id = %s - AND (s.expires_at IS NULL OR s.expires_at > NOW())) - ORDER BY b.created_at DESC - """, (user_id, user_id, user_id)) - rows = await cursor.fetchall() - - return [ - BotResponse( - id=str(row[0]), # 使用 UUID 主键 - name=row[1], - bot_id=str(row[0]), # bot_id 也指向主键 id - is_owner=(row[6] is not None and str(row[6]) == user_id), - is_shared=(row[6] is not None and str(row[6]) != user_id and row[8] is not None), - is_published=row[11] if row[11] else False, - copied_from=str(row[12]) if row[12] else None, - owner={"id": str(row[6]), "username": row[7]} if row[6] is not None else None, - role=row[8] if row[8] is not None else None, - shared_at=datetime_to_str(row[9]) if row[9] is not None else None, - expires_at=row[10].isoformat() if row[10] is not None else None, - description=row[5].get('description') if row[5] else None, - avatar_url=row[5].get('avatar_url') if row[5] else None, - created_at=datetime_to_str(row[3]), - updated_at=datetime_to_str(row[4]) - ) - for row in rows - ] + return [ + BotResponse( + id=str(row[0]), + name=row[1], + bot_id=str(row[0]), + is_owner=(row[6] is not None and str(row[6]) == user_id), + is_shared=(row[6] is not None and str(row[6]) != user_id and row[8] is not None), + is_published=row[11] if row[11] else False, + copied_from=str(row[12]) if row[12] else None, + owner={"id": str(row[6]), "username": row[7]} if row[6] is not None else None, + role=row[8] if row[8] is not None else None, + shared_at=datetime_to_str(row[9]) if row[9] is not None else None, + expires_at=row[10].isoformat() if row[10] is not None else None, + description=row[5].get('description') if row[5] else None, + avatar_url=row[5].get('avatar_url') if row[5] else None, + created_at=datetime_to_str(row[3]), + updated_at=datetime_to_str(row[4]) + ) + for row in rows + ] @router.post("/api/v1/bots", response_model=BotResponse)