perf👌: webui完善好友群组管理api,添加部分数据库管理接口

This commit is contained in:
HibiKier
2024-01-14 05:20:21 +08:00
parent bf55a20241
commit 59cb2bee8b
5 changed files with 109 additions and 45 deletions
+25 -1
View File
@@ -17,7 +17,7 @@ from ....utils import authentication
from .models.model import SqlModel, SqlText from .models.model import SqlModel, SqlText
from .models.sql_log import SqlLog from .models.sql_log import SqlLog
router = APIRouter() router = APIRouter(prefix="/database")
driver: Driver = nonebot.get_driver() driver: Driver = nonebot.get_driver()
@@ -26,6 +26,18 @@ driver: Driver = nonebot.get_driver()
SQL_DICT = {} SQL_DICT = {}
SELECT_TABLE_SQL = """
select a.tablename as name,d.description as desc from pg_tables a
left join pg_class c on relname=tablename
left join pg_description d on oid=objoid and objsubid=0 where a.schemaname = 'public'
"""
SELECT_TABLE_COLUMN_SQL = """
SELECT column_name, data_type, character_maximum_length as max_length, is_nullable
FROM information_schema.columns
WHERE table_name = '{}';
"""
@driver.on_startup @driver.on_startup
async def _(): async def _():
for matcher in get_matchers(True): for matcher in get_matchers(True):
@@ -45,6 +57,18 @@ async def _():
) )
SQL_DICT[plugin_name] = SqlModel SQL_DICT[plugin_name] = SqlModel
@router.get("/get_table_list", dependencies=[authentication()], description="获取数据库表")
async def _() -> Result:
db = Tortoise.get_connection("default")
query = await db.execute_query_dict(SELECT_TABLE_SQL)
return Result.ok(query)
@router.get("/get_table_column", dependencies=[authentication()], description="获取表字段")
async def _(table_name: str) -> Result:
db = Tortoise.get_connection("default")
print(SELECT_TABLE_COLUMN_SQL.format(table_name))
query = await db.execute_query_dict(SELECT_TABLE_COLUMN_SQL.format(table_name))
return Result.ok(query)
@router.post("/exec_sql", dependencies=[authentication()], description="执行sql") @router.post("/exec_sql", dependencies=[authentication()], description="执行sql")
async def _(sql: SqlText, request: Request) -> Result: async def _(sql: SqlText, request: Request) -> Result:
+2 -2
View File
@@ -25,7 +25,7 @@ from .model import ActiveGroup, BaseInfo, ChatHistoryCount, HotPlugin
run_time = time.time() run_time = time.time()
ws_router = APIRouter() ws_router = APIRouter()
router = APIRouter() router = APIRouter(prefix="/main")
@@ -183,7 +183,7 @@ async def _(date_type: Optional[QueryDateType] = None) -> Result:
if date_type == QueryDateType.YEAR: if date_type == QueryDateType.YEAR:
query = ChatHistory.filter(create_time__gte=now - timedelta(days=365)) query = ChatHistory.filter(create_time__gte=now - timedelta(days=365))
data_list = ( data_list = (
await query.annotate(count=Count("id")) await query.annotate(count=Count("id")).filter(group_id__not_isnull=True)
.group_by("group_id").order_by("-count").limit(5) .group_by("group_id").order_by("-count").limit(5)
.values_list("group_id", "count") .values_list("group_id", "count")
) )
+64 -36
View File
@@ -33,6 +33,7 @@ from .model import (
HandleRequest, HandleRequest,
LeaveGroup, LeaveGroup,
Message, Message,
MessageItem,
Plugin, Plugin,
ReqResult, ReqResult,
SendMessage, SendMessage,
@@ -42,7 +43,7 @@ from .model import (
) )
ws_router = APIRouter() ws_router = APIRouter()
router = APIRouter() router = APIRouter(prefix="/manage")
SUB_PATTERN = r"\x1b(\[.*?[@-~]|\].*?(\x07|\x1b\\))" SUB_PATTERN = r"\x1b(\[.*?[@-~]|\].*?(\x07|\x1b\\))"
@@ -50,6 +51,8 @@ GROUP_PATTERN = r'.*?Message (-?\d*) from (\d*)@\[群:(\d*)] "(.*)"'
PRIVATE_PATTERN = r'.*?Message (-?\d*) from (\d*) "(.*)"' PRIVATE_PATTERN = r'.*?Message (-?\d*) from (\d*) "(.*)"'
IMAGE_PATTERN = r'\[CQ:image,.*,url=(.*);.*?\]'
@router.get("/get_group_list", dependencies=[authentication()], description="获取群组列表") @router.get("/get_group_list", dependencies=[authentication()], description="获取群组列表")
async def _(bot_id: str) -> Result: async def _(bot_id: str) -> Result:
""" """
@@ -323,8 +326,10 @@ async def _(bot_id: str, group_id: str) -> Result:
like_plugin[name] = data[1] like_plugin[name] = data[1]
close_plugins = [] close_plugins = []
for module in g.close_plugins: for module in g.close_plugins:
plugin = Plugin(module=module, plugin_name=module) module_ = module.replace(":super", "")
if plugin_data := plugin_data_manager.get(module): is_super_block = module.endswith(":super")
plugin = Plugin(module=module_, plugin_name=module, is_super_block=is_super_block)
if plugin_data := plugin_data_manager.get(module_):
plugin.plugin_name = plugin_data.name plugin.plugin_name = plugin_data.name
close_plugins.append(plugin) close_plugins.append(plugin)
task_list = [] task_list = []
@@ -374,48 +379,71 @@ async def _(param: SendMessage) -> Result:
MSG_LIST = [] MSG_LIST = []
ID2NAME = {}
async def message_handle(sub_log: str, type: Literal["private", "group"]):
global MSG_LIST, ID2NAME
pattern = PRIVATE_PATTERN if type == 'private' else GROUP_PATTERN
msg_id = None
uid = None
gid = None
msg = None
img_list = re.findall(IMAGE_PATTERN, sub_log)
if r := re.search(pattern, sub_log):
if type == 'private':
msg_id = r.group(1)
uid = r.group(2)
msg = r.group(3)
if uid not in ID2NAME:
user = await FriendUser.filter(user_id=uid).first()
ID2NAME[uid] = user.user_name or user.nickname
else:
msg_id = r.group(1)
uid = r.group(2)
gid = r.group(3)
msg = r.group(4)
if gid not in ID2NAME:
user = await GroupInfoUser.filter(user_id=uid, group_id=gid).first()
ID2NAME[gid] = user.user_name or user.nickname
if msg_id in MSG_LIST:
return
MSG_LIST.append(msg_id)
messages = []
rep = re.split(r'\[CQ:image.*\]', msg)
if img_list:
for i in range(len(rep)):
messages.append(MessageItem(type="text", msg=rep[i]))
if i < len(img_list):
messages.append(MessageItem(type="img", msg=img_list[i]))
else:
messages = [MessageItem(type="text", msg=x) for x in rep]
return Message(
object_id=uid if type == 'private' else gid,
user_id=uid,
group_id=gid,
message=messages,
name=ID2NAME[uid],
ava_url=AVA_URL.format(uid),
)
@ws_router.websocket("/chat") @ws_router.websocket("/chat")
async def _(websocket: WebSocket, group_id: Optional[str] = None, user_id: Optional[str] = None): async def _(websocket: WebSocket):
global MSG_LIST
await websocket.accept() await websocket.accept()
async def log_listener(log: str): async def log_listener(log: str):
global MSG_LIST, ID2NAME
sub_log = re.sub(SUB_PATTERN, "", log) sub_log = re.sub(SUB_PATTERN, "", log)
img_list = re.findall(IMAGE_PATTERN, sub_log)
if "message.private.friend" in log: if "message.private.friend" in log:
if r := re.search(PRIVATE_PATTERN, sub_log): if message := await message_handle(sub_log, 'private'):
msg_id = r.group(1) await websocket.send_json(message.dict())
uid = r.group(2)
msg = r.group(3)
user = await FriendUser.filter(user_id=user_id).first()
name = user.user_name
if uid and uid == user_id and msg_id not in MSG_LIST:
MSG_LIST.append(msg_id)
message = Message(
user_id=uid,
message=msg,
name=name,
ava_url=AVA_URL.format(uid)
)
await websocket.send_json(message.dict())
else: else:
if r := re.search(GROUP_PATTERN, sub_log): if r := re.search(GROUP_PATTERN, sub_log):
msg_id = r.group(1) if message := await message_handle(sub_log, 'group'):
uid = r.group(2)
gid = r.group(3)
msg = r.group(4)
user = await GroupInfoUser.filter(user_id=uid, group_id=gid).first()
name = user.user_name or user.nickname
if gid and gid == group_id and msg_id not in MSG_LIST:
MSG_LIST.append(msg_id)
message = Message(
user_id=uid,
group_id=gid,
message=msg,
name=name,
ava_url=AVA_URL.format(uid)
)
await websocket.send_json(message.dict()) await websocket.send_json(message.dict())
if len(MSG_LIST) > 30:
MSG_LIST = MSG_LIST[-1:]
LOG_STORAGE.listeners.add(log_listener) LOG_STORAGE.listeners.add(log_listener)
try: try:
while websocket.client_state == WebSocketState.CONNECTED: while websocket.client_state == WebSocketState.CONNECTED:
+13 -1
View File
@@ -41,6 +41,8 @@ class Plugin(BaseModel):
"""模块名""" """模块名"""
plugin_name: str plugin_name: str
"""中文名""" """中文名"""
is_super_block: bool
"""是否超级用户禁用"""
class GroupResult(BaseModel): class GroupResult(BaseModel):
@@ -227,23 +229,33 @@ class GroupDetail(BaseModel):
task: List[Task] task: List[Task]
"""被动列表""" """被动列表"""
class MessageItem(BaseModel):
type: str
"""消息类型"""
msg: str
"""内容"""
class Message(BaseModel): class Message(BaseModel):
""" """
消息 消息
""" """
object_id: str
"""主体id user_id 或 group_id"""
user_id: str user_id: str
"""用户id""" """用户id"""
group_id: Optional[str] = None group_id: Optional[str] = None
"""群组id""" """群组id"""
message: str message: List[MessageItem]
"""消息""" """消息"""
name: str name: str
"""用户名称""" """用户名称"""
ava_url: str ava_url: str
"""用户头像""" """用户头像"""
class SendMessage(BaseModel): class SendMessage(BaseModel):
""" """
发送消息 发送消息
@@ -2,7 +2,7 @@ import re
from typing import List, Optional from typing import List, Optional
import cattrs import cattrs
from fastapi import APIRouter from fastapi import APIRouter, Query
from configs.config import Config from configs.config import Config
from services.log import logger from services.log import logger
@@ -17,26 +17,26 @@ from .model import (
PluginDetail, PluginDetail,
PluginInfo, PluginInfo,
PluginSwitch, PluginSwitch,
UpdateConfig,
UpdatePlugin, UpdatePlugin,
) )
router = APIRouter() router = APIRouter(prefix="/plugin")
@router.get("/get_plugin_list", dependencies=[authentication()], deprecated="获取插件列表") @router.get("/get_plugin_list", dependencies=[authentication()], deprecated="获取插件列表")
def _( def _(
plugin_type: PluginType, menu_type: Optional[str] = None plugin_type: List[PluginType] = Query(None), menu_type: Optional[str] = None
) -> Result: ) -> Result:
""" """
获取插件列表 获取插件列表
:param plugin_type: 类型 normal, superuser, hidden, admin :param plugin_type: 类型 normal, superuser, hidden, admin
:param menu_type: 菜单类型
""" """
try: try:
plugin_list: List[PluginInfo] = [] plugin_list: List[PluginInfo] = []
for module in plugin_data_manager.keys(): for module in plugin_data_manager.keys():
plugin_data: Optional[PluginData] = plugin_data_manager[module] plugin_data: Optional[PluginData] = plugin_data_manager[module]
if plugin_data and plugin_data.plugin_type == plugin_type: if plugin_data and plugin_data.plugin_type in plugin_type:
setting = plugin_data.plugin_setting or PluginSetting() setting = plugin_data.plugin_setting or PluginSetting()
plugin = plugin_data.plugin_status plugin = plugin_data.plugin_status
menu_type_ = getattr(setting, "plugin_type", ["无"])[0] menu_type_ = getattr(setting, "plugin_type", ["无"])[0]