mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-07-16 01:16:07 +00:00
feat(platform): migrate bot admins from config.yaml to database (#2289)
* feat(platform): migrate bot admins from config.yaml to database - Add BotAdmin ORM model (bot_admins table) scoped per bot_uuid - Add Alembic migration 0007 to create table and migrate legacy config admins - Remove top-level admins key from config.yaml template - Add GET/POST/DELETE /api/v1/platform/bots/<uuid>/admins endpoints - Update cmdmgr privilege check to query bot_admins table (bot-scoped) - Add BotAdminsPanel frontend component in bot detail sessions tab - Add i18n keys (zh-Hans, en-US) * fix(ci): ruff/prettier format, fix test_importutil assertion * fix(ci): prettier format BackendClient.ts and i18n locales * fix(ci): eslint-prettier fix BackendClient.ts single-param formatting * refactor: move admin management into session monitor, fix session_id enum format - Remove standalone admins tab, replace with BotAdminsDialog in session monitor - Add admin toggle button inline in chat header next to Active status - Add BotAdminsDialog component with useBotAdmins hook - Fix session_id written as LauncherTypes.PERSON_xxx instead of person_xxx (monitoring_helper.py x4, pipelinemgr.py x1 missing .value on launcher_type) - Fix duplicate platform/person label in session list and chat header - Migrate existing malformed session_id records in DB --------- Co-authored-by: dadachann <185672915+dadachann@users.noreply.github.com>
This commit is contained in:
@@ -18,7 +18,6 @@ class BotsRouterGroup(group.RouterGroup):
|
||||
@self.route('/<bot_uuid>', methods=['GET', 'PUT', 'DELETE'], auth_type=group.AuthType.USER_TOKEN_OR_API_KEY)
|
||||
async def _(bot_uuid: str) -> str:
|
||||
if quart.request.method == 'GET':
|
||||
# 返回运行时信息,包括webhook地址等
|
||||
bot = await self.ap.bot_service.get_runtime_bot_info(bot_uuid)
|
||||
if bot is None:
|
||||
return self.http_status(404, -1, 'bot not found')
|
||||
@@ -37,30 +36,21 @@ class BotsRouterGroup(group.RouterGroup):
|
||||
from_index = json_data.get('from_index', -1)
|
||||
max_count = json_data.get('max_count', 10)
|
||||
logs, total_count = await self.ap.bot_service.list_event_logs(bot_uuid, from_index, max_count)
|
||||
return self.success(
|
||||
data={
|
||||
'logs': logs,
|
||||
'total_count': total_count,
|
||||
}
|
||||
)
|
||||
return self.success(data={'logs': logs, 'total_count': total_count})
|
||||
|
||||
@self.route('/<bot_uuid>/send_message', methods=['POST'], auth_type=group.AuthType.API_KEY)
|
||||
async def _(bot_uuid: str) -> str:
|
||||
"""Send message to a specific target via bot"""
|
||||
json_data = await quart.request.json
|
||||
target_type = json_data.get('target_type')
|
||||
target_id = json_data.get('target_id')
|
||||
message_chain_data = json_data.get('message_chain')
|
||||
|
||||
# Validate required fields
|
||||
if not target_type:
|
||||
return self.http_status(400, -1, 'target_type is required')
|
||||
if not target_id:
|
||||
return self.http_status(400, -1, 'target_id is required')
|
||||
if not message_chain_data:
|
||||
return self.http_status(400, -1, 'message_chain is required')
|
||||
|
||||
# Validate target_type
|
||||
if target_type not in ['person', 'group']:
|
||||
return self.http_status(400, -1, 'target_type must be either "person" or "group"')
|
||||
|
||||
@@ -72,3 +62,29 @@ class BotsRouterGroup(group.RouterGroup):
|
||||
|
||||
traceback.print_exc()
|
||||
return self.http_status(500, -1, f'Failed to send message: {str(e)}')
|
||||
|
||||
# ============ Bot Admins ============
|
||||
|
||||
@self.route('/<bot_uuid>/admins', methods=['GET', 'POST'], auth_type=group.AuthType.USER_TOKEN_OR_API_KEY)
|
||||
async def _(bot_uuid: str) -> str:
|
||||
if quart.request.method == 'GET':
|
||||
admins = await self.ap.bot_service.get_bot_admins(bot_uuid)
|
||||
return self.success(data={'admins': admins})
|
||||
elif quart.request.method == 'POST':
|
||||
json_data = await quart.request.json
|
||||
launcher_type = json_data.get('launcher_type', '').strip()
|
||||
launcher_id = str(json_data.get('launcher_id', '')).strip()
|
||||
if not launcher_type or not launcher_id:
|
||||
return self.http_status(400, -1, 'launcher_type and launcher_id are required')
|
||||
try:
|
||||
admin_id = await self.ap.bot_service.add_bot_admin(bot_uuid, launcher_type, launcher_id)
|
||||
return self.success(data={'id': admin_id})
|
||||
except Exception as e:
|
||||
return self.http_status(409, -1, str(e))
|
||||
|
||||
@self.route(
|
||||
'/<bot_uuid>/admins/<int:admin_id>', methods=['DELETE'], auth_type=group.AuthType.USER_TOKEN_OR_API_KEY
|
||||
)
|
||||
async def _(bot_uuid: str, admin_id: int) -> str:
|
||||
await self.ap.bot_service.delete_bot_admin(bot_uuid, admin_id)
|
||||
return self.success()
|
||||
|
||||
@@ -199,3 +199,35 @@ class BotService:
|
||||
|
||||
# Send message via adapter
|
||||
await runtime_bot.adapter.send_message(target_type, str(target_id), message_chain)
|
||||
|
||||
# ============ Bot Admins ============
|
||||
|
||||
async def get_bot_admins(self, bot_uuid: str) -> list[dict]:
|
||||
from ....entity.persistence import bot as persistence_bot
|
||||
|
||||
result = await self.ap.persistence_mgr.execute_async(
|
||||
sqlalchemy.select(persistence_bot.BotAdmin).where(persistence_bot.BotAdmin.bot_uuid == bot_uuid)
|
||||
)
|
||||
return [{'id': r.id, 'launcher_type': r.launcher_type, 'launcher_id': r.launcher_id} for r in result.all()]
|
||||
|
||||
async def add_bot_admin(self, bot_uuid: str, launcher_type: str, launcher_id: str) -> int:
|
||||
from ....entity.persistence import bot as persistence_bot
|
||||
|
||||
result = await self.ap.persistence_mgr.execute_async(
|
||||
sqlalchemy.insert(persistence_bot.BotAdmin).values(
|
||||
bot_uuid=bot_uuid,
|
||||
launcher_type=launcher_type,
|
||||
launcher_id=launcher_id,
|
||||
)
|
||||
)
|
||||
return result.inserted_primary_key[0]
|
||||
|
||||
async def delete_bot_admin(self, bot_uuid: str, admin_id: int) -> None:
|
||||
from ....entity.persistence import bot as persistence_bot
|
||||
|
||||
await self.ap.persistence_mgr.execute_async(
|
||||
sqlalchemy.delete(persistence_bot.BotAdmin).where(
|
||||
persistence_bot.BotAdmin.bot_uuid == bot_uuid,
|
||||
persistence_bot.BotAdmin.id == admin_id,
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user