From 1ae9e689fefad66b6e4f0a1314eb645673b834ff Mon Sep 17 00:00:00 2001
From: HibiKier <775757368@qq.com>
Date: Mon, 23 Dec 2024 17:33:49 +0800
Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20=20=E4=BC=98=E5=8C=96Web=20UI?=
=?UTF-8?q?=E4=BB=A3=E7=A0=81=E7=BB=93=E6=9E=84=EF=BC=8C=E4=BF=AE=E6=94=B9?=
=?UTF-8?q?target=E6=96=B9=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
zhenxun/builtin_plugins/__init__.py | 8 -
zhenxun/builtin_plugins/restart/__init__.py | 2 +-
.../superuser/broadcast/_data_source.py | 2 +-
zhenxun/builtin_plugins/web_ui/__init__.py | 4 +-
.../web_ui/api/tabs/dashboard/__init__.py | 149 ++----
.../web_ui/api/tabs/dashboard/data_source.py | 166 ++++++-
.../web_ui/api/tabs/database/__init__.py | 138 ++----
.../web_ui/api/tabs/database/data_source.py | 90 ++++
.../web_ui/api/tabs/main/__init__.py | 302 +++---------
.../web_ui/api/tabs/main/data_source.py | 337 ++++++++++++-
.../web_ui/api/tabs/manage/__init__.py | 455 ++++++------------
.../web_ui/api/tabs/manage/chat.py | 19 +-
.../web_ui/api/tabs/manage/data_source.py | 274 +++++++++++
.../web_ui/api/tabs/manage/model.py | 2 +-
.../web_ui/api/tabs/plugin_manage/__init__.py | 198 +++-----
.../api/tabs/plugin_manage/data_source.py | 153 ++++++
zhenxun/services/__init__.py | 8 +
zhenxun/utils/platform.py | 8 +-
18 files changed, 1389 insertions(+), 926 deletions(-)
create mode 100644 zhenxun/builtin_plugins/web_ui/api/tabs/database/data_source.py
create mode 100644 zhenxun/builtin_plugins/web_ui/api/tabs/manage/data_source.py
create mode 100644 zhenxun/builtin_plugins/web_ui/api/tabs/plugin_manage/data_source.py
diff --git a/zhenxun/builtin_plugins/__init__.py b/zhenxun/builtin_plugins/__init__.py
index bead7254..aaa8306d 100644
--- a/zhenxun/builtin_plugins/__init__.py
+++ b/zhenxun/builtin_plugins/__init__.py
@@ -2,20 +2,12 @@ from datetime import datetime
import uuid
import nonebot
-from nonebot import require
from nonebot.adapters import Bot
from nonebot.drivers import Driver
from tortoise import Tortoise
from tortoise.exceptions import OperationalError
import ujson as json
-require("nonebot_plugin_apscheduler")
-require("nonebot_plugin_alconna")
-require("nonebot_plugin_session")
-require("nonebot_plugin_userinfo")
-require("nonebot_plugin_htmlrender")
-# require("nonebot_plugin_uninfo")
-
from zhenxun.models.bot_connect_log import BotConnectLog
from zhenxun.models.bot_console import BotConsole
from zhenxun.models.goods_info import GoodsInfo
diff --git a/zhenxun/builtin_plugins/restart/__init__.py b/zhenxun/builtin_plugins/restart/__init__.py
index 314404c3..b24a2345 100644
--- a/zhenxun/builtin_plugins/restart/__init__.py
+++ b/zhenxun/builtin_plugins/restart/__init__.py
@@ -89,7 +89,7 @@ async def _(bot: Bot):
async with aiofiles.open(RESTART_MARK, encoding="utf8") as f:
bot_id, user_id = (await f.read()).split()
if bot := nonebot.get_bot(bot_id):
- if target := PlatformUtils.get_target(bot, user_id):
+ if target := PlatformUtils.get_target(user_id=user_id):
await MessageUtils.build_message(
f"{BotConfig.self_nickname}已成功重启!"
).send(target, bot=bot)
diff --git a/zhenxun/builtin_plugins/superuser/broadcast/_data_source.py b/zhenxun/builtin_plugins/superuser/broadcast/_data_source.py
index 195fc429..540eaeff 100644
--- a/zhenxun/builtin_plugins/superuser/broadcast/_data_source.py
+++ b/zhenxun/builtin_plugins/superuser/broadcast/_data_source.py
@@ -47,7 +47,7 @@ class BroadcastManage:
group.group_id,
):
target = PlatformUtils.get_target(
- bot, None, group.channel_id or group.group_id
+ group_id=group.group_id, channel_id=group.channel_id
)
if target:
await MessageUtils.build_message(message_list).send(
diff --git a/zhenxun/builtin_plugins/web_ui/__init__.py b/zhenxun/builtin_plugins/web_ui/__init__.py
index bbea8708..f855b8a4 100644
--- a/zhenxun/builtin_plugins/web_ui/__init__.py
+++ b/zhenxun/builtin_plugins/web_ui/__init__.py
@@ -112,6 +112,6 @@ async def _():
app.include_router(BaseApiRouter)
app.include_router(WsApiRouter)
await init_public(app)
- logger.info("API启动成功", "Web UI")
+ logger.info("API启动成功", "WebUi")
except Exception as e:
- logger.error("API启动失败", "Web UI", e=e)
+ logger.error("API启动失败", "WebUi", e=e)
diff --git a/zhenxun/builtin_plugins/web_ui/api/tabs/dashboard/__init__.py b/zhenxun/builtin_plugins/web_ui/api/tabs/dashboard/__init__.py
index fba85be1..81b66185 100644
--- a/zhenxun/builtin_plugins/web_ui/api/tabs/dashboard/__init__.py
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/dashboard/__init__.py
@@ -1,20 +1,14 @@
-from datetime import datetime, timedelta
-
from fastapi import APIRouter
from fastapi.responses import JSONResponse
import nonebot
from nonebot import require
from nonebot.config import Config
-from tortoise.expressions import RawSQL
-from tortoise.functions import Count
-from zhenxun.models.bot_connect_log import BotConnectLog
-from zhenxun.models.chat_history import ChatHistory
-from zhenxun.models.statistics import Statistics
+from zhenxun.services.log import logger
from ....base_model import BaseResultModel, QueryModel, Result
from ....utils import authentication
-from .data_source import BotManage
+from .data_source import ApiDataSource
from .model import AllChatAndCallCount, BotInfo, ChatCallMonthCount, QueryChatCallCount
require("plugin_store")
@@ -33,8 +27,9 @@ driver = nonebot.get_driver()
)
async def _() -> Result[list[BotInfo]]:
try:
- return Result.ok(await BotManage.get_bot_list(), "拿到信息啦!")
+ return Result.ok(await ApiDataSource.get_bot_list(), "拿到信息啦!")
except Exception as e:
+ logger.error(f"{router.prefix}/get_bot_list 调用错误", "WebUi", e=e)
return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@@ -46,29 +41,13 @@ async def _() -> Result[list[BotInfo]]:
description="获取聊天/调用记录的全部和今日数量",
)
async def _(bot_id: str | None = None) -> Result[QueryChatCallCount]:
- now = datetime.now()
- query = ChatHistory
- if bot_id:
- query = query.filter(bot_id=bot_id)
- chat_all_count = await query.annotate().count()
- chat_day_count = await query.filter(
- create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
- ).count()
- query = Statistics
- if bot_id:
- query = query.filter(bot_id=bot_id)
- call_all_count = await query.annotate().count()
- call_day_count = await query.filter(
- create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
- ).count()
- return Result.ok(
- QueryChatCallCount(
- chat_num=chat_all_count,
- chat_day=chat_day_count,
- call_num=call_all_count,
- call_day=call_day_count,
+ try:
+ return Result.ok(
+ await ApiDataSource.get_chat_and_call_count(bot_id), "拿到信息啦!"
)
- )
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_chat_and_call_count 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.get(
@@ -79,41 +58,15 @@ async def _(bot_id: str | None = None) -> Result[QueryChatCallCount]:
description="获取聊天/调用记录的全部数据次数",
)
async def _(bot_id: str | None = None) -> Result[AllChatAndCallCount]:
- now = datetime.now()
- query = ChatHistory
- if bot_id:
- query = query.filter(bot_id=bot_id)
- chat_week_count = await query.filter(
- create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
- ).count()
- chat_month_count = await query.filter(
- create_time__gte=now - timedelta(days=30, hours=now.hour, minutes=now.minute)
- ).count()
- chat_year_count = await query.filter(
- create_time__gte=now - timedelta(days=365, hours=now.hour, minutes=now.minute)
- ).count()
- query = Statistics
- if bot_id:
- query = query.filter(bot_id=bot_id)
- call_week_count = await query.filter(
- create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
- ).count()
- call_month_count = await query.filter(
- create_time__gte=now - timedelta(days=30, hours=now.hour, minutes=now.minute)
- ).count()
- call_year_count = await query.filter(
- create_time__gte=now - timedelta(days=365, hours=now.hour, minutes=now.minute)
- ).count()
- return Result.ok(
- AllChatAndCallCount(
- chat_week=chat_week_count,
- chat_month=chat_month_count,
- chat_year=chat_year_count,
- call_week=call_week_count,
- call_month=call_month_count,
- call_year=call_year_count,
+ try:
+ return Result.ok(
+ await ApiDataSource.get_all_chat_and_call_count(bot_id), "拿到信息啦!"
)
- )
+ except Exception as e:
+ logger.error(
+ f"{router.prefix}/get_all_chat_and_call_count 调用错误", "WebUi", e=e
+ )
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.get(
@@ -124,48 +77,13 @@ async def _(bot_id: str | None = None) -> Result[AllChatAndCallCount]:
deprecated="获取聊天/调用记录的一个月数量", # type: ignore
)
async def _(bot_id: str | None = None) -> Result[ChatCallMonthCount]:
- now = datetime.now()
- filter_date = now - timedelta(days=30, hours=now.hour, minutes=now.minute)
- chat_query = ChatHistory
- call_query = Statistics
- if bot_id:
- chat_query = chat_query.filter(bot_id=bot_id)
- call_query = call_query.filter(bot_id=bot_id)
- chat_date_list = (
- await chat_query.filter(create_time__gte=filter_date)
- .annotate(date=RawSQL("DATE(create_time)"), count=Count("id"))
- .group_by("date")
- .values("date", "count")
- )
- call_date_list = (
- await call_query.filter(create_time__gte=filter_date)
- .annotate(date=RawSQL("DATE(create_time)"), count=Count("id"))
- .group_by("date")
- .values("date", "count")
- )
- date_list = []
- chat_count_list = []
- call_count_list = []
- chat_date2cnt = {str(date["date"]): date["count"] for date in chat_date_list}
- call_date2cnt = {str(date["date"]): date["count"] for date in call_date_list}
- date = now.date()
- for _ in range(30):
- if str(date) in chat_date2cnt:
- chat_count_list.append(chat_date2cnt[str(date)])
- else:
- chat_count_list.append(0)
- if str(date) in call_date2cnt:
- call_count_list.append(call_date2cnt[str(date)])
- else:
- call_count_list.append(0)
- date_list.append(str(date)[5:])
- date -= timedelta(days=1)
- chat_count_list.reverse()
- call_count_list.reverse()
- date_list.reverse()
- return Result.ok(
- ChatCallMonthCount(chat=chat_count_list, call=call_count_list, date=date_list)
- )
+ try:
+ return Result.ok(
+ await ApiDataSource.get_chat_and_call_month(bot_id), "拿到信息啦!"
+ )
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_chat_and_call_month 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.post(
@@ -176,18 +94,11 @@ async def _(bot_id: str | None = None) -> Result[ChatCallMonthCount]:
deprecated="获取Bot连接记录", # type: ignore
)
async def _(query: QueryModel) -> Result[BaseResultModel]:
- total = await BotConnectLog.all().count()
- if total % query.size:
- total += 1
- data = (
- await BotConnectLog.all()
- .order_by("-id")
- .offset((query.index - 1) * query.size)
- .limit(query.size)
- )
- for v in data:
- v.connect_time = v.connect_time.replace(tzinfo=None).replace(microsecond=0)
- return Result.ok(BaseResultModel(total=total, data=data))
+ try:
+ return Result.ok(await ApiDataSource.get_connect_log(query), "拿到信息啦!")
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_connect_log 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.get(
diff --git a/zhenxun/builtin_plugins/web_ui/api/tabs/dashboard/data_source.py b/zhenxun/builtin_plugins/web_ui/api/tabs/dashboard/data_source.py
index e033561b..243dafc2 100644
--- a/zhenxun/builtin_plugins/web_ui/api/tabs/dashboard/data_source.py
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/dashboard/data_source.py
@@ -4,13 +4,17 @@ import time
import nonebot
from nonebot.adapters import Bot
from nonebot.drivers import Driver
+from tortoise.expressions import RawSQL
+from tortoise.functions import Count
+from zhenxun.models.bot_connect_log import BotConnectLog
from zhenxun.models.chat_history import ChatHistory
from zhenxun.models.statistics import Statistics
from zhenxun.utils.platform import PlatformUtils
+from ....base_model import BaseResultModel, QueryModel
from ..main.data_source import bot_live
-from .model import BotInfo
+from .model import AllChatAndCallCount, BotInfo, ChatCallMonthCount, QueryChatCallCount
driver: Driver = nonebot.get_driver()
@@ -24,7 +28,7 @@ async def _():
CONNECT_TIME = int(time.time())
-class BotManage:
+class ApiDataSource:
@classmethod
async def __build_bot_info(cls, bot: Bot) -> BotInfo:
"""构建Bot信息
@@ -76,3 +80,161 @@ class BotManage:
for _, bot in nonebot.get_bots().items():
bot_list.append(await cls.__build_bot_info(bot))
return bot_list
+
+ @classmethod
+ async def get_chat_and_call_count(cls, bot_id: str | None) -> QueryChatCallCount:
+ """获取今日聊天和调用次数
+
+ 参数:
+ bot_id: bot id
+
+ 返回:
+ QueryChatCallCount: 数据内容
+ """
+ now = datetime.now()
+ query = ChatHistory
+ if bot_id:
+ query = query.filter(bot_id=bot_id)
+ chat_all_count = await query.annotate().count()
+ chat_day_count = await query.filter(
+ create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
+ ).count()
+ query = Statistics
+ if bot_id:
+ query = query.filter(bot_id=bot_id)
+ call_all_count = await query.annotate().count()
+ call_day_count = await query.filter(
+ create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
+ ).count()
+ return QueryChatCallCount(
+ chat_num=chat_all_count,
+ chat_day=chat_day_count,
+ call_num=call_all_count,
+ call_day=call_day_count,
+ )
+
+ @classmethod
+ async def get_all_chat_and_call_count(
+ cls, bot_id: str | None
+ ) -> AllChatAndCallCount:
+ """获取全部聊天和调用记录
+
+ 参数:
+ bot_id: bot id
+
+ 返回:
+ AllChatAndCallCount: 数据内容
+ """
+ now = datetime.now()
+ query = ChatHistory
+ if bot_id:
+ query = query.filter(bot_id=bot_id)
+ chat_week_count = await query.filter(
+ create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
+ ).count()
+ chat_month_count = await query.filter(
+ create_time__gte=now
+ - timedelta(days=30, hours=now.hour, minutes=now.minute)
+ ).count()
+ chat_year_count = await query.filter(
+ create_time__gte=now
+ - timedelta(days=365, hours=now.hour, minutes=now.minute)
+ ).count()
+ query = Statistics
+ if bot_id:
+ query = query.filter(bot_id=bot_id)
+ call_week_count = await query.filter(
+ create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
+ ).count()
+ call_month_count = await query.filter(
+ create_time__gte=now
+ - timedelta(days=30, hours=now.hour, minutes=now.minute)
+ ).count()
+ call_year_count = await query.filter(
+ create_time__gte=now
+ - timedelta(days=365, hours=now.hour, minutes=now.minute)
+ ).count()
+ return AllChatAndCallCount(
+ chat_week=chat_week_count,
+ chat_month=chat_month_count,
+ chat_year=chat_year_count,
+ call_week=call_week_count,
+ call_month=call_month_count,
+ call_year=call_year_count,
+ )
+
+ @classmethod
+ async def get_chat_and_call_month(cls, bot_id: str | None) -> ChatCallMonthCount:
+ """获取一个月内的调用/消息记录次数,并根据日期对数据填充0
+
+ 参数:
+ bot_id: bot id
+
+ 返回:
+ ChatCallMonthCount: 数据内容
+ """
+ now = datetime.now()
+ filter_date = now - timedelta(days=30, hours=now.hour, minutes=now.minute)
+ chat_query = ChatHistory
+ call_query = Statistics
+ if bot_id:
+ chat_query = chat_query.filter(bot_id=bot_id)
+ call_query = call_query.filter(bot_id=bot_id)
+ chat_date_list = (
+ await chat_query.filter(create_time__gte=filter_date)
+ .annotate(date=RawSQL("DATE(create_time)"), count=Count("id"))
+ .group_by("date")
+ .values("date", "count")
+ )
+ call_date_list = (
+ await call_query.filter(create_time__gte=filter_date)
+ .annotate(date=RawSQL("DATE(create_time)"), count=Count("id"))
+ .group_by("date")
+ .values("date", "count")
+ )
+ date_list = []
+ chat_count_list = []
+ call_count_list = []
+ chat_date2cnt = {str(date["date"]): date["count"] for date in chat_date_list}
+ call_date2cnt = {str(date["date"]): date["count"] for date in call_date_list}
+ date = now.date()
+ for _ in range(30):
+ if str(date) in chat_date2cnt:
+ chat_count_list.append(chat_date2cnt[str(date)])
+ else:
+ chat_count_list.append(0)
+ if str(date) in call_date2cnt:
+ call_count_list.append(call_date2cnt[str(date)])
+ else:
+ call_count_list.append(0)
+ date_list.append(str(date)[5:])
+ date -= timedelta(days=1)
+ chat_count_list.reverse()
+ call_count_list.reverse()
+ date_list.reverse()
+ return ChatCallMonthCount(
+ chat=chat_count_list, call=call_count_list, date=date_list
+ )
+
+ @classmethod
+ async def get_connect_log(cls, query: QueryModel) -> BaseResultModel:
+ """获取bot连接日志
+
+ 参数:
+ query: 查询模型
+
+ 返回:
+ BaseResultModel: 数据内容
+ """
+ total = await BotConnectLog.all().count()
+ if total % query.size:
+ total += 1
+ data = (
+ await BotConnectLog.all()
+ .order_by("-id")
+ .offset((query.index - 1) * query.size)
+ .limit(query.size)
+ )
+ for v in data:
+ v.connect_time = v.connect_time.replace(tzinfo=None).replace(microsecond=0)
+ return BaseResultModel(total=total, data=data)
diff --git a/zhenxun/builtin_plugins/web_ui/api/tabs/database/__init__.py b/zhenxun/builtin_plugins/web_ui/api/tabs/database/__init__.py
index efabfdfa..c9713422 100644
--- a/zhenxun/builtin_plugins/web_ui/api/tabs/database/__init__.py
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/database/__init__.py
@@ -8,9 +8,11 @@ from tortoise.exceptions import OperationalError
from zhenxun.configs.config import BotConfig
from zhenxun.models.plugin_info import PluginInfo
from zhenxun.models.task_info import TaskInfo
+from zhenxun.services.log import logger
from ....base_model import BaseResultModel, QueryModel, Result
from ....utils import authentication
+from .data_source import ApiDataSource, type2sql
from .models.model import Column, SqlModel, SqlText
from .models.sql_log import SqlLog
@@ -20,52 +22,6 @@ router = APIRouter(prefix="/database")
driver: Driver = nonebot.get_driver()
-SQL_DICT = {}
-
-
-SELECT_TABLE_MYSQL_SQL = """
-SELECT table_name AS name, table_comment AS `desc`
-FROM information_schema.tables
-WHERE table_schema = DATABASE();
-"""
-
-SELECT_TABLE_SQLITE_SQL = """
-SELECT name FROM sqlite_master WHERE type='table';
-"""
-
-SELECT_TABLE_PSQL_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_PSQL_SQL = """
-SELECT column_name, data_type, character_maximum_length as max_length, is_nullable
-FROM information_schema.columns
-WHERE table_name = '{}';
-"""
-
-SELECT_TABLE_COLUMN_MYSQL_SQL = """
-SHOW COLUMNS FROM {};
-"""
-
-SELECT_TABLE_COLUMN_SQLITE_SQL = """
-PRAGMA table_info({});
-"""
-
-type2sql = {
- "mysql": SELECT_TABLE_MYSQL_SQL,
- "sqlite": SELECT_TABLE_SQLITE_SQL,
- "postgres": SELECT_TABLE_PSQL_SQL,
-}
-
-type2sql_column = {
- "mysql": SELECT_TABLE_COLUMN_MYSQL_SQL,
- "sqlite": SELECT_TABLE_COLUMN_SQLITE_SQL,
- "postgres": SELECT_TABLE_COLUMN_PSQL_SQL,
-}
-
-
@driver.on_startup
async def _():
for plugin in nonebot.get_loaded_plugins():
@@ -73,7 +29,7 @@ async def _():
sql_list = []
if plugin.metadata and plugin.metadata.extra:
sql_list = plugin.metadata.extra.get("sql_list")
- if module in SQL_DICT:
+ if module in ApiDataSource.SQL_DICT:
raise ValueError(f"{module} 常用SQL module 重复")
if sql_list:
SqlModel(
@@ -81,15 +37,15 @@ async def _():
module=module,
sql_list=sql_list,
)
- SQL_DICT[module] = SqlModel
- if SQL_DICT:
- result = await PluginInfo.filter(module__in=SQL_DICT.keys()).values_list(
- "module", "name"
- )
+ ApiDataSource.SQL_DICT[module] = SqlModel
+ if ApiDataSource.SQL_DICT:
+ result = await PluginInfo.filter(
+ module__in=ApiDataSource.SQL_DICT.keys()
+ ).values_list("module", "name")
module2name = {r[0]: r[1] for r in result}
- for s in SQL_DICT:
- module = SQL_DICT[s].module
- SQL_DICT[s].name = module2name.get(module, module)
+ for s in ApiDataSource.SQL_DICT:
+ module = ApiDataSource.SQL_DICT[s].module
+ ApiDataSource.SQL_DICT[s].name = module2name.get(module, module)
@router.get(
@@ -100,10 +56,14 @@ async def _():
description="获取数据库表",
)
async def _() -> Result[list[dict]]:
- db = Tortoise.get_connection("default")
- sql_type = BotConfig.get_sql_type()
- query = await db.execute_query_dict(type2sql[sql_type])
- return Result.ok(query)
+ try:
+ db = Tortoise.get_connection("default")
+ sql_type = BotConfig.get_sql_type()
+ query = await db.execute_query_dict(type2sql[sql_type])
+ return Result.ok(query)
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_table_list 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.get(
@@ -114,34 +74,13 @@ async def _() -> Result[list[dict]]:
description="获取表字段",
)
async def _(table_name: str) -> Result[list[Column]]:
- db = Tortoise.get_connection("default")
- sql_type = BotConfig.get_sql_type()
- sql = type2sql_column[sql_type]
- query = await db.execute_query_dict(sql.format(table_name))
- result_list = []
- if sql_type == "sqlite":
- result_list.extend(
- Column(
- column_name=result["name"],
- data_type=result["type"],
- max_length=-1,
- is_nullable="YES" if result["notnull"] == 1 else "NO",
- )
- for result in query
+ try:
+ return Result.ok(
+ await ApiDataSource.get_table_column(table_name), "拿到信息啦!"
)
- elif sql_type == "mysql":
- result_list.extend(
- Column(
- column_name=result["Field"],
- data_type=result["Type"],
- max_length=-1,
- is_nullable=result["Null"],
- )
- for result in query
- )
- else:
- result_list.extend(Column(**result) for result in query)
- return Result.ok(result_list)
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_table_column 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.post(
@@ -163,7 +102,8 @@ async def _(sql: SqlText, request: Request) -> Result[list[dict]]:
result = await TaskInfo.raw(sql.sql)
await SqlLog.add(ip or "0.0.0.0", sql.sql, str(result))
return Result.ok(info="执行成功啦!")
- except OperationalError as e:
+ except Exception as e:
+ logger.error(f"{router.prefix}/exec_sql 调用错误", "WebUi", e=e)
await SqlLog.add(ip or "0.0.0.0", sql.sql, str(e), False)
return Result.warning_(f"sql执行错误: {e}")
@@ -176,16 +116,20 @@ async def _(sql: SqlText, request: Request) -> Result[list[dict]]:
description="sql日志列表",
)
async def _(query: QueryModel) -> Result[BaseResultModel]:
- total = await SqlLog.all().count()
- if total % query.size:
- total += 1
- data = (
- await SqlLog.all()
- .order_by("-id")
- .offset((query.index - 1) * query.size)
- .limit(query.size)
- )
- return Result.ok(BaseResultModel(total=total, data=data))
+ try:
+ total = await SqlLog.all().count()
+ if total % query.size:
+ total += 1
+ data = (
+ await SqlLog.all()
+ .order_by("-id")
+ .offset((query.index - 1) * query.size)
+ .limit(query.size)
+ )
+ return Result.ok(BaseResultModel(total=total, data=data))
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_sql_log 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.get(
diff --git a/zhenxun/builtin_plugins/web_ui/api/tabs/database/data_source.py b/zhenxun/builtin_plugins/web_ui/api/tabs/database/data_source.py
new file mode 100644
index 00000000..9e937837
--- /dev/null
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/database/data_source.py
@@ -0,0 +1,90 @@
+from tortoise import Tortoise
+
+from zhenxun.configs.config import BotConfig
+
+from .models.model import Column
+
+SELECT_TABLE_MYSQL_SQL = """
+SELECT table_name AS name, table_comment AS `desc`
+FROM information_schema.tables
+WHERE table_schema = DATABASE();
+"""
+
+SELECT_TABLE_SQLITE_SQL = """
+SELECT name FROM sqlite_master WHERE type='table';
+"""
+
+SELECT_TABLE_PSQL_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_PSQL_SQL = """
+SELECT column_name, data_type, character_maximum_length as max_length, is_nullable
+FROM information_schema.columns
+WHERE table_name = '{}';
+"""
+
+SELECT_TABLE_COLUMN_MYSQL_SQL = """
+SHOW COLUMNS FROM {};
+"""
+
+SELECT_TABLE_COLUMN_SQLITE_SQL = """
+PRAGMA table_info({});
+"""
+
+type2sql = {
+ "mysql": SELECT_TABLE_MYSQL_SQL,
+ "sqlite": SELECT_TABLE_SQLITE_SQL,
+ "postgres": SELECT_TABLE_PSQL_SQL,
+}
+
+type2sql_column = {
+ "mysql": SELECT_TABLE_COLUMN_MYSQL_SQL,
+ "sqlite": SELECT_TABLE_COLUMN_SQLITE_SQL,
+ "postgres": SELECT_TABLE_COLUMN_PSQL_SQL,
+}
+
+
+class ApiDataSource:
+ SQL_DICT = {} # noqa: RUF012
+
+ @classmethod
+ async def get_table_column(cls, table_name: str) -> list[Column]:
+ """获取表字段信息
+
+ 参数:
+ table_name: 表名
+
+ 返回:
+ list[Column]: 字段数据
+ """
+ db = Tortoise.get_connection("default")
+ sql_type = BotConfig.get_sql_type()
+ sql = type2sql_column[sql_type]
+ query = await db.execute_query_dict(sql.format(table_name))
+ result_list = []
+ if sql_type == "sqlite":
+ result_list.extend(
+ Column(
+ column_name=result["name"],
+ data_type=result["type"],
+ max_length=-1,
+ is_nullable="YES" if result["notnull"] == 1 else "NO",
+ )
+ for result in query
+ )
+ elif sql_type == "mysql":
+ result_list.extend(
+ Column(
+ column_name=result["Field"],
+ data_type=result["Type"],
+ max_length=-1,
+ is_nullable=result["Null"],
+ )
+ for result in query
+ )
+ else:
+ result_list.extend(Column(**result) for result in query)
+ return result_list
diff --git a/zhenxun/builtin_plugins/web_ui/api/tabs/main/__init__.py b/zhenxun/builtin_plugins/web_ui/api/tabs/main/__init__.py
index f21bd61c..98eff79f 100644
--- a/zhenxun/builtin_plugins/web_ui/api/tabs/main/__init__.py
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/main/__init__.py
@@ -1,7 +1,5 @@
import asyncio
import contextlib
-from datetime import datetime, timedelta
-from pathlib import Path
import time
from fastapi import APIRouter
@@ -9,25 +7,17 @@ from fastapi.responses import JSONResponse
import nonebot
from nonebot.config import Config
from starlette.websockets import WebSocket, WebSocketDisconnect, WebSocketState
-from tortoise.functions import Count
from websockets.exceptions import ConnectionClosedError, ConnectionClosedOK
-from zhenxun.models.bot_connect_log import BotConnectLog
from zhenxun.models.bot_console import BotConsole
-from zhenxun.models.chat_history import ChatHistory
-from zhenxun.models.group_console import GroupConsole
-from zhenxun.models.plugin_info import PluginInfo
-from zhenxun.models.statistics import Statistics
-from zhenxun.models.task_info import TaskInfo
from zhenxun.services.log import logger
from zhenxun.utils.common_utils import CommonUtils
-from zhenxun.utils.enum import PluginType
from zhenxun.utils.platform import PlatformUtils
from ....base_model import Result
-from ....config import AVA_URL, GROUP_AVA_URL, QueryDateType
+from ....config import QueryDateType
from ....utils import authentication, get_system_status
-from .data_source import bot_live
+from .data_source import ApiDataSource
from .model import (
ActiveGroup,
BaseInfo,
@@ -37,7 +27,6 @@ from .model import (
HotPlugin,
NonebotData,
QueryCount,
- TemplateBaseInfo,
)
driver = nonebot.get_driver()
@@ -63,64 +52,14 @@ async def _(bot_id: str | None = None) -> Result[list[BaseInfo]]:
返回:
Result: 获取指定bot信息与bot列表
"""
- global run_time
- bot_list: list[TemplateBaseInfo] = []
- if bots := nonebot.get_bots():
- select_bot: BaseInfo
- for _, bot in bots.items():
- login_info = None
- try:
- login_info = await bot.get_login_info()
- except Exception as e:
- logger.warning("调用接口get_login_info失败", "webui", e=e)
- bot_list.append(
- TemplateBaseInfo(
- bot=bot, # type: ignore
- self_id=bot.self_id,
- nickname=login_info["nickname"] if login_info else bot.self_id,
- ava_url=AVA_URL.format(bot.self_id),
- )
- )
- # 获取指定qq号的bot信息,若无指定 则获取第一个
- if _bl := [b for b in bot_list if b.self_id == bot_id]:
- select_bot = _bl[0]
- else:
- select_bot = bot_list[0]
- select_bot.is_select = True
- now = datetime.now()
- # 今日累计接收消息
- select_bot.received_messages = await ChatHistory.filter(
- bot_id=select_bot.self_id,
- create_time__gte=now - timedelta(hours=now.hour),
- ).count()
- # 群聊数量
- select_bot.group_count = len(await PlatformUtils.get_group_list(select_bot.bot))
- # 好友数量
- select_bot.friend_count = len(
- await PlatformUtils.get_friend_list(select_bot.bot)
- )
- for bot in bot_list:
- bot.bot = None # type: ignore
- select_bot.status = await BotConsole.get_bot_status(select_bot.self_id)
- # 连接时间
- select_bot.connect_time = bot_live.get(select_bot.self_id) or 0
- if select_bot.connect_time:
- connect_date = datetime.fromtimestamp(select_bot.connect_time)
- select_bot.connect_date = connect_date.strftime("%Y-%m-%d %H:%M:%S")
- version_file = Path() / "__version__"
- if version_file.exists():
- if text := version_file.open().read():
- if ver := text.replace("__version__: ", "").strip():
- select_bot.version = ver
- day_call = await Statistics.filter(
- create_time__gte=now - timedelta(hours=now.hour)
- ).count()
- select_bot.day_call = day_call
- select_bot.connect_count = await BotConnectLog.filter(
- bot_id=select_bot.self_id
- ).count()
- return Result.ok([BaseInfo(**e.dict()) for e in bot_list], "拿到信息啦!")
- return Result.warning_("无Bot连接...")
+ try:
+ result = await ApiDataSource.get_base_info(bot_id)
+ if not result:
+ Result.warning_("无Bot连接...")
+ return Result.ok(result, "拿到信息啦!")
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_base_info 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.get(
@@ -131,32 +70,11 @@ async def _(bot_id: str | None = None) -> Result[list[BaseInfo]]:
description="获取接收消息数量",
)
async def _(bot_id: str | None = None) -> Result[QueryCount]:
- now = datetime.now()
- query = ChatHistory
- if bot_id:
- query = query.filter(bot_id=bot_id)
- all_count = await query.annotate().count()
- day_count = await query.filter(
- create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
- ).count()
- week_count = await query.filter(
- create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
- ).count()
- month_count = await query.filter(
- create_time__gte=now - timedelta(days=30, hours=now.hour, minutes=now.minute)
- ).count()
- year_count = await query.filter(
- create_time__gte=now - timedelta(days=365, hours=now.hour, minutes=now.minute)
- ).count()
- return Result.ok(
- QueryCount(
- num=all_count,
- day=day_count,
- week=week_count,
- month=month_count,
- year=year_count,
- )
- )
+ try:
+ return Result.ok(await ApiDataSource.get_all_chat_count(bot_id), "拿到信息啦!")
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_all_chat_count 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.get(
@@ -167,32 +85,11 @@ async def _(bot_id: str | None = None) -> Result[QueryCount]:
description="获取调用次数",
)
async def _(bot_id: str | None = None) -> Result[QueryCount]:
- now = datetime.now()
- query = Statistics
- if bot_id:
- query = query.filter(bot_id=bot_id)
- all_count = await query.annotate().count()
- day_count = await query.filter(
- create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
- ).count()
- week_count = await query.filter(
- create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
- ).count()
- month_count = await query.filter(
- create_time__gte=now - timedelta(days=30, hours=now.hour, minutes=now.minute)
- ).count()
- year_count = await query.filter(
- create_time__gte=now - timedelta(days=365, hours=now.hour, minutes=now.minute)
- ).count()
- return Result.ok(
- QueryCount(
- num=all_count,
- day=day_count,
- week=week_count,
- month=month_count,
- year=year_count,
- )
- )
+ try:
+ return Result.ok(await ApiDataSource.get_all_call_count(bot_id), "拿到信息啦!")
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_all_call_count 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.get(
@@ -203,19 +100,18 @@ async def _(bot_id: str | None = None) -> Result[QueryCount]:
description="好友/群组数量",
)
async def _(bot_id: str) -> Result[dict[str, int]]:
- if bots := nonebot.get_bots():
- if bot_id not in bots:
- return Result.warning_("指定Bot未连接...")
- bot = bots[bot_id]
- platform = PlatformUtils.get_platform(bot)
- if platform == "qq":
- data = {
- "friend_count": len(await bot.get_friend_list()),
- "group_count": len(await bot.get_group_list()),
- }
- return Result.ok(data)
- return Result.warning_("暂不支持该平台...")
- return Result.warning_("无Bot连接...")
+ try:
+ bot = nonebot.get_bot(bot_id)
+ data = {
+ "friend_count": len(await PlatformUtils.get_friend_list(bot)),
+ "group_count": len(await PlatformUtils.get_group_list(bot)),
+ }
+ return Result.ok(data, "拿到信息啦!")
+ except ValueError:
+ return Result.warning_("指定Bot未连接...")
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_fg_count 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.get(
@@ -226,6 +122,7 @@ async def _(bot_id: str) -> Result[dict[str, int]]:
description="获取nb数据",
)
async def _() -> Result[NonebotData]:
+ global run_time
return Result.ok(NonebotData(config=driver.config, run_time=int(run_time)))
@@ -248,6 +145,7 @@ async def _() -> Result[Config]:
description="获取nb运行时间",
)
async def _() -> Result[int]:
+ global run_time
return Result.ok(int(run_time))
@@ -261,48 +159,13 @@ async def _() -> Result[int]:
async def _(
date_type: QueryDateType | None = None, bot_id: str | None = None
) -> Result[list[ActiveGroup]]:
- query = ChatHistory
- now = datetime.now()
- if bot_id:
- query = query.filter(bot_id=bot_id)
- if date_type == QueryDateType.DAY:
- query = query.filter(create_time__gte=now - timedelta(hours=now.hour))
- if date_type == QueryDateType.WEEK:
- query = query.filter(create_time__gte=now - timedelta(days=7))
- if date_type == QueryDateType.MONTH:
- query = query.filter(create_time__gte=now - timedelta(days=30))
- if date_type == QueryDateType.YEAR:
- query = query.filter(create_time__gte=now - timedelta(days=365))
- data_list = (
- await query.annotate(count=Count("id"))
- .filter(group_id__not_isnull=True)
- .group_by("group_id")
- .order_by("-count")
- .limit(5)
- .values_list("group_id", "count")
- )
- id2name = {}
- if data_list:
- if info_list := await GroupConsole.filter(
- group_id__in=[x[0] for x in data_list]
- ).all():
- for group_info in info_list:
- id2name[group_info.group_id] = group_info.group_name
- active_group_list = [
- ActiveGroup(
- group_id=data[0],
- name=id2name.get(data[0]) or data[0],
- chat_num=data[1],
- ava_img=GROUP_AVA_URL.format(data[0], data[0]),
+ try:
+ return Result.ok(
+ await ApiDataSource.get_active_group(date_type, bot_id), "拿到信息啦!"
)
- for data in data_list
- ]
- active_group_list = sorted(
- active_group_list, key=lambda x: x.chat_num, reverse=True
- )
- if len(active_group_list) > 5:
- active_group_list = active_group_list[:5]
- return Result.ok(active_group_list)
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_active_group 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.get(
@@ -315,37 +178,13 @@ async def _(
async def _(
date_type: QueryDateType | None = None, bot_id: str | None = None
) -> Result[list[HotPlugin]]:
- query = Statistics
- now = datetime.now()
- if bot_id:
- query = query.filter(bot_id=bot_id)
- if date_type == QueryDateType.DAY:
- query = query.filter(create_time__gte=now - timedelta(hours=now.hour))
- if date_type == QueryDateType.WEEK:
- query = query.filter(create_time__gte=now - timedelta(days=7))
- if date_type == QueryDateType.MONTH:
- query = query.filter(create_time__gte=now - timedelta(days=30))
- if date_type == QueryDateType.YEAR:
- query = query.filter(create_time__gte=now - timedelta(days=365))
- data_list = (
- await query.annotate(count=Count("id"))
- .group_by("plugin_name")
- .order_by("-count")
- .limit(5)
- .values_list("plugin_name", "count")
- )
- hot_plugin_list = []
- module_list = [x[0] for x in data_list]
- plugins = await PluginInfo.filter(module__in=module_list).all()
- module2name = {p.module: p.name for p in plugins}
- for data in data_list:
- module = data[0]
- name = module2name.get(module) or module
- hot_plugin_list.append(HotPlugin(module=module, name=name, count=data[1]))
- hot_plugin_list = sorted(hot_plugin_list, key=lambda x: x.count, reverse=True)
- if len(hot_plugin_list) > 5:
- hot_plugin_list = hot_plugin_list[:5]
- return Result.ok(hot_plugin_list)
+ try:
+ return Result.ok(
+ await ApiDataSource.get_hot_plugin(date_type, bot_id), "拿到信息啦!"
+ )
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_hot_plugin 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.post(
@@ -368,37 +207,16 @@ async def _(param: BotStatusParam):
dependencies=[authentication()],
response_model=Result[BotBlockModule],
response_class=JSONResponse,
- description="修改bot全局开关",
+ description="获取bot层面的禁用模块",
)
async def _(bot_id: str) -> Result[BotBlockModule]:
try:
- bot_data = await BotConsole.get_or_none(bot_id=bot_id)
- if not bot_data:
- return Result.fail("Bot数据不存在...")
- block_tasks = []
- block_plugins = []
- all_plugins = await PluginInfo.filter(
- load_status=True, plugin_type=PluginType.NORMAL
- ).values("module", "name")
- all_task = await TaskInfo.annotate().values("module", "name")
- if bot_data.block_tasks:
- tasks = CommonUtils.convert_module_format(bot_data.block_tasks)
- block_tasks = [t["module"] for t in all_task if t["module"] in tasks]
- if bot_data.block_plugins:
- plugins = CommonUtils.convert_module_format(bot_data.block_plugins)
- block_plugins = [t["module"] for t in all_plugins if t["module"] in plugins]
return Result.ok(
- BotBlockModule(
- bot_id=bot_id,
- block_tasks=block_tasks,
- block_plugins=block_plugins,
- all_plugins=all_plugins,
- all_tasks=all_task,
- )
+ await ApiDataSource.get_bot_block_module(bot_id), "拿到信息啦!"
)
except Exception as e:
- logger.error("获取Bot数据失败", "webui", e=e)
- return Result.fail(f"获取Bot数据失败 {type(e)}:{e}...")
+ logger.error(f"{router.prefix}/get_bot_block_module 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.post(
@@ -409,13 +227,17 @@ async def _(bot_id: str) -> Result[BotBlockModule]:
description="修改bot全局开关",
)
async def _(param: BotManageUpdateParam):
- bot_data = await BotConsole.get_or_none(bot_id=param.bot_id)
- if not bot_data:
- return Result.fail("Bot数据不存在...")
- bot_data.block_plugins = CommonUtils.convert_module_format(param.block_plugins)
- bot_data.block_tasks = CommonUtils.convert_module_format(param.block_tasks)
- await bot_data.save(update_fields=["block_plugins", "block_tasks"])
- return Result.ok()
+ try:
+ bot_data = await BotConsole.get_or_none(bot_id=param.bot_id)
+ if not bot_data:
+ return Result.fail("Bot数据不存在...")
+ bot_data.block_plugins = CommonUtils.convert_module_format(param.block_plugins)
+ bot_data.block_tasks = CommonUtils.convert_module_format(param.block_tasks)
+ await bot_data.save(update_fields=["block_plugins", "block_tasks"])
+ return Result.ok()
+ except Exception as e:
+ logger.error(f"{router.prefix}/update_bot_manage 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@ws_router.websocket("/system_status")
diff --git a/zhenxun/builtin_plugins/web_ui/api/tabs/main/data_source.py b/zhenxun/builtin_plugins/web_ui/api/tabs/main/data_source.py
index ca445016..79bbc5c0 100644
--- a/zhenxun/builtin_plugins/web_ui/api/tabs/main/data_source.py
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/main/data_source.py
@@ -1,8 +1,33 @@
+from datetime import datetime, timedelta
+from pathlib import Path
import time
import nonebot
-from nonebot.adapters.onebot.v11 import Bot
+from nonebot.adapters import Bot
from nonebot.drivers import Driver
+from tortoise.functions import Count
+
+from zhenxun.models.bot_connect_log import BotConnectLog
+from zhenxun.models.bot_console import BotConsole
+from zhenxun.models.chat_history import ChatHistory
+from zhenxun.models.group_console import GroupConsole
+from zhenxun.models.plugin_info import PluginInfo
+from zhenxun.models.statistics import Statistics
+from zhenxun.models.task_info import TaskInfo
+from zhenxun.services.log import logger
+from zhenxun.utils.common_utils import CommonUtils
+from zhenxun.utils.enum import PluginType
+from zhenxun.utils.platform import PlatformUtils
+
+from ....config import AVA_URL, GROUP_AVA_URL, QueryDateType
+from .model import (
+ ActiveGroup,
+ BaseInfo,
+ BotBlockModule,
+ HotPlugin,
+ QueryCount,
+ TemplateBaseInfo,
+)
driver: Driver = nonebot.get_driver()
@@ -33,3 +58,313 @@ async def _(bot: Bot):
@driver.on_bot_disconnect
async def _(bot: Bot):
bot_live.remove(bot.self_id)
+
+
+class ApiDataSource:
+ @classmethod
+ async def __build_bot_info(cls, bot: Bot) -> TemplateBaseInfo:
+ """构建bot信息
+
+ 参数:
+ bot: bot实例
+
+ 返回:
+ TemplateBaseInfo: bot信息
+ """
+ login_info = None
+ try:
+ login_info = await bot.get_login_info()
+ except Exception as e:
+ logger.warning("调用接口get_login_info失败", "WebUi", e=e)
+ return TemplateBaseInfo(
+ bot=bot,
+ self_id=bot.self_id,
+ nickname=login_info["nickname"] if login_info else bot.self_id,
+ ava_url=AVA_URL.format(bot.self_id),
+ )
+
+ @classmethod
+ def __get_bot_version(cls) -> str:
+ """获取bot版本
+
+ 返回:
+ str | None: 版本
+ """
+ version_file = Path() / "__version__"
+ if version_file.exists():
+ if text := version_file.open().read():
+ return text.replace("__version__: ", "").strip()
+ return "unknown"
+
+ @classmethod
+ async def __init_bot_base_data(cls, select_bot: TemplateBaseInfo):
+ """初始化bot的基础数据
+
+ 参数:
+ select_bot: bot
+ """
+ now = datetime.now()
+ # 今日累计接收消息
+ select_bot.received_messages = await ChatHistory.filter(
+ bot_id=select_bot.self_id,
+ create_time__gte=now - timedelta(hours=now.hour),
+ ).count()
+ # 群聊数量
+ select_bot.group_count = len(await PlatformUtils.get_group_list(select_bot.bot))
+ # 好友数量
+ select_bot.friend_count = len(
+ await PlatformUtils.get_friend_list(select_bot.bot)
+ )
+ select_bot.status = await BotConsole.get_bot_status(select_bot.self_id)
+ # 连接时间
+ select_bot.connect_time = bot_live.get(select_bot.self_id) or 0
+ if select_bot.connect_time:
+ connect_date = datetime.fromtimestamp(select_bot.connect_time)
+ select_bot.connect_date = connect_date.strftime("%Y-%m-%d %H:%M:%S")
+ select_bot.version = cls.__get_bot_version()
+ day_call = await Statistics.filter(
+ create_time__gte=now - timedelta(hours=now.hour)
+ ).count()
+ select_bot.day_call = day_call
+ select_bot.connect_count = await BotConnectLog.filter(
+ bot_id=select_bot.self_id
+ ).count()
+
+ @classmethod
+ async def get_base_info(cls, bot_id: str | None) -> list[BaseInfo] | None:
+ """获取bot信息
+
+ 参数:
+ bot_id: bot id
+
+ 返回:
+ list[BaseInfo] | None: bot列表
+ """
+ bots = nonebot.get_bots()
+ if not bots:
+ return None
+ select_bot: BaseInfo
+ bot_list = [await cls.__build_bot_info(bot) for _, bot in bots.items()]
+ # 获取指定qq号的bot信息,若无指定 则获取第一个
+ if _bl := [b for b in bot_list if b.self_id == bot_id]:
+ select_bot = _bl[0]
+ else:
+ select_bot = bot_list[0]
+ await cls.__init_bot_base_data(select_bot)
+ for bot in bot_list:
+ bot.bot = None # type: ignore
+ select_bot.is_select = True
+ return [BaseInfo(**e.dict()) for e in bot_list]
+
+ @classmethod
+ async def get_all_chat_count(cls, bot_id: str | None) -> QueryCount:
+ """获取年/月/周/日聊天次数
+
+ 参数:
+ bot_id: bot id
+
+ 返回:
+ QueryCount: 数据内容
+ """
+ now = datetime.now()
+ query = ChatHistory
+ if bot_id:
+ query = query.filter(bot_id=bot_id)
+ all_count = await query.annotate().count()
+ day_count = await query.filter(
+ create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
+ ).count()
+ week_count = await query.filter(
+ create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
+ ).count()
+ month_count = await query.filter(
+ create_time__gte=now
+ - timedelta(days=30, hours=now.hour, minutes=now.minute)
+ ).count()
+ year_count = await query.filter(
+ create_time__gte=now
+ - timedelta(days=365, hours=now.hour, minutes=now.minute)
+ ).count()
+ return QueryCount(
+ num=all_count,
+ day=day_count,
+ week=week_count,
+ month=month_count,
+ year=year_count,
+ )
+
+ @classmethod
+ async def get_all_call_count(cls, bot_id: str | None) -> QueryCount:
+ """获取年/月/周/日调用次数
+
+ 参数:
+ bot_id: bot id
+
+ 返回:
+ QueryCount: 数据内容
+ """
+ now = datetime.now()
+ query = Statistics
+ if bot_id:
+ query = query.filter(bot_id=bot_id)
+ all_count = await query.annotate().count()
+ day_count = await query.filter(
+ create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
+ ).count()
+ week_count = await query.filter(
+ create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
+ ).count()
+ month_count = await query.filter(
+ create_time__gte=now
+ - timedelta(days=30, hours=now.hour, minutes=now.minute)
+ ).count()
+ year_count = await query.filter(
+ create_time__gte=now
+ - timedelta(days=365, hours=now.hour, minutes=now.minute)
+ ).count()
+ return QueryCount(
+ num=all_count,
+ day=day_count,
+ week=week_count,
+ month=month_count,
+ year=year_count,
+ )
+
+ @classmethod
+ def __get_query(
+ cls,
+ base_query: type[ChatHistory | Statistics],
+ date_type: QueryDateType | None = None,
+ bot_id: str | None = None,
+ ):
+ """构建日期查询条件
+
+ 参数:
+ date_type: 日期类型.
+ bot_id: bot id.
+ """
+ query = base_query
+ now = datetime.now()
+ if bot_id:
+ query = query.filter(bot_id=bot_id)
+ if date_type == QueryDateType.DAY:
+ query = query.filter(create_time__gte=now - timedelta(hours=now.hour))
+ if date_type == QueryDateType.WEEK:
+ query = query.filter(create_time__gte=now - timedelta(days=7))
+ if date_type == QueryDateType.MONTH:
+ query = query.filter(create_time__gte=now - timedelta(days=30))
+ if date_type == QueryDateType.YEAR:
+ query = query.filter(create_time__gte=now - timedelta(days=365))
+ return query
+
+ @classmethod
+ async def get_active_group(
+ cls, date_type: QueryDateType | None = None, bot_id: str | None = None
+ ) -> list[ActiveGroup]:
+ """获取活跃群组
+
+ 参数:
+ date_type: 日期类型.
+ bot_id: bot id.
+
+ 返回:
+ list[ActiveGroup]: 活跃群组列表
+ """
+ query = cls.__get_query(ChatHistory, date_type, bot_id)
+ data_list = (
+ await query.annotate(count=Count("id"))
+ .filter(group_id__not_isnull=True)
+ .group_by("group_id")
+ .order_by("-count")
+ .limit(5)
+ .values_list("group_id", "count")
+ )
+ id2name = {}
+ if data_list:
+ if info_list := await GroupConsole.filter(
+ group_id__in=[x[0] for x in data_list]
+ ).all():
+ for group_info in info_list:
+ id2name[group_info.group_id] = group_info.group_name
+ active_group_list = [
+ ActiveGroup(
+ group_id=data[0],
+ name=id2name.get(data[0]) or data[0],
+ chat_num=data[1],
+ ava_img=GROUP_AVA_URL.format(data[0], data[0]),
+ )
+ for data in data_list
+ ]
+ active_group_list = sorted(
+ active_group_list, key=lambda x: x.chat_num, reverse=True
+ )
+ if len(active_group_list) > 5:
+ active_group_list = active_group_list[:5]
+ return active_group_list
+
+ @classmethod
+ async def get_hot_plugin(
+ cls, date_type: QueryDateType | None = None, bot_id: str | None = None
+ ) -> list[HotPlugin]:
+ """获取热门插件
+
+ 参数:
+ date_type: 日期类型.
+ bot_id: bot id.
+
+ 返回:
+ list[HotPlugin]: 热门插件列表
+ """
+ query = cls.__get_query(Statistics, date_type, bot_id)
+ data_list = (
+ await query.annotate(count=Count("id"))
+ .group_by("plugin_name")
+ .order_by("-count")
+ .limit(5)
+ .values_list("plugin_name", "count")
+ )
+ hot_plugin_list = []
+ module_list = [x[0] for x in data_list]
+ plugins = await PluginInfo.filter(module__in=module_list).all()
+ module2name = {p.module: p.name for p in plugins}
+ for data in data_list:
+ module = data[0]
+ name = module2name.get(module) or module
+ hot_plugin_list.append(HotPlugin(module=module, name=name, count=data[1]))
+ hot_plugin_list = sorted(hot_plugin_list, key=lambda x: x.count, reverse=True)
+ if len(hot_plugin_list) > 5:
+ hot_plugin_list = hot_plugin_list[:5]
+ return hot_plugin_list
+
+ @classmethod
+ async def get_bot_block_module(cls, bot_id: str) -> BotBlockModule | None:
+ """获取bot层面的禁用模块
+
+ 参数:
+ bot_id: bot id
+
+ 返回:
+ BotBlockModule | None: 数据内容
+ """
+ bot_data = await BotConsole.get_or_none(bot_id=bot_id)
+ if not bot_data:
+ return None
+ block_tasks = []
+ block_plugins = []
+ all_plugins = await PluginInfo.filter(
+ load_status=True, plugin_type=PluginType.NORMAL
+ ).values("module", "name")
+ all_task = await TaskInfo.annotate().values("module", "name")
+ if bot_data.block_tasks:
+ tasks = CommonUtils.convert_module_format(bot_data.block_tasks)
+ block_tasks = [t["module"] for t in all_task if t["module"] in tasks]
+ if bot_data.block_plugins:
+ plugins = CommonUtils.convert_module_format(bot_data.block_plugins)
+ block_plugins = [t["module"] for t in all_plugins if t["module"] in plugins]
+ return BotBlockModule(
+ bot_id=bot_id,
+ block_tasks=block_tasks,
+ block_plugins=block_plugins,
+ all_plugins=all_plugins,
+ all_tasks=all_task,
+ )
diff --git a/zhenxun/builtin_plugins/web_ui/api/tabs/manage/__init__.py b/zhenxun/builtin_plugins/web_ui/api/tabs/manage/__init__.py
index 90db6935..78a37e08 100644
--- a/zhenxun/builtin_plugins/web_ui/api/tabs/manage/__init__.py
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/manage/__init__.py
@@ -2,18 +2,10 @@ from fastapi import APIRouter
from fastapi.responses import JSONResponse
import nonebot
from nonebot.adapters.onebot.v11 import ActionFailed
-from tortoise.functions import Count
-from zhenxun.configs.config import BotConfig
-from zhenxun.models.ban_console import BanConsole
-from zhenxun.models.chat_history import ChatHistory
from zhenxun.models.fg_request import FgRequest
from zhenxun.models.group_console import GroupConsole
-from zhenxun.models.plugin_info import PluginInfo
-from zhenxun.models.statistics import Statistics
-from zhenxun.models.task_info import TaskInfo
from zhenxun.services.log import logger
-from zhenxun.utils.common_utils import CommonUtils
from zhenxun.utils.enum import RequestHandleType, RequestType
from zhenxun.utils.exception import NotFoundError
from zhenxun.utils.platform import PlatformUtils
@@ -21,20 +13,17 @@ from zhenxun.utils.platform import PlatformUtils
from ....base_model import Result
from ....config import AVA_URL, GROUP_AVA_URL
from ....utils import authentication
+from .data_source import ApiDataSource
from .model import (
ClearRequest,
DeleteFriend,
Friend,
- FriendRequestResult,
GroupDetail,
- GroupRequestResult,
GroupResult,
HandleRequest,
LeaveGroup,
- Plugin,
ReqResult,
- SendMessage,
- Task,
+ SendMessageParam,
UpdateGroup,
UserDetail,
)
@@ -53,17 +42,19 @@ async def _(bot_id: str) -> Result:
"""
获取群信息
"""
- if not (bots := nonebot.get_bots()):
- return Result.warning_("无Bot连接...")
- if bot_id not in bots:
- return Result.warning_("指定Bot未连接...")
group_list_result = []
try:
- group_list = await bots[bot_id].get_group_list()
+ bot = nonebot.get_bot(bot_id)
+ group_list, _ = await PlatformUtils.get_group_list(bot)
for g in group_list:
- gid = g["group_id"]
- g["ava_url"] = GROUP_AVA_URL.format(gid, gid)
- group_list_result.append(GroupResult(**g))
+ ava_url = GROUP_AVA_URL.format(g.group_id, g.group_id)
+ group_list_result.append(
+ GroupResult(
+ group_id=g.group_id, group_name=g.group_name, ava_url=ava_url
+ )
+ )
+ except ValueError:
+ return Result.warning_("指定Bot未连接...")
except Exception as e:
logger.error("调用API错误", "/get_group_list", e=e)
return Result.fail(f"{type(e)}: {e}")
@@ -79,29 +70,11 @@ async def _(bot_id: str) -> Result:
)
async def _(group: UpdateGroup) -> Result[str]:
try:
- group_id = group.group_id
- if db_group := await GroupConsole.get_group(group_id):
- task_list = await TaskInfo.all().values_list("module", flat=True)
- db_group.level = group.level
- db_group.status = group.status
- if group.close_plugins:
- db_group.block_plugin = CommonUtils.convert_module_format(
- group.close_plugins
- )
- else:
- db_group.block_plugin = ""
- if group.task:
- if block_task := [t for t in task_list if t not in group.task]:
- db_group.block_task = CommonUtils.convert_module_format(block_task) # type: ignore
- else:
- db_group.block_task = CommonUtils.convert_module_format(task_list) # type: ignore
- await db_group.save(
- update_fields=["level", "status", "block_plugin", "block_task"]
- )
+ await ApiDataSource.update_group(group)
+ return Result.ok(info="已完成记录!")
except Exception as e:
- logger.error("调用API错误", "/get_group", e=e)
- return Result.fail(f"{type(e)}: {e}")
- return Result.ok(info="已完成记录!")
+ logger.error(f"{router.prefix}/update_group 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.get(
@@ -115,24 +88,24 @@ async def _(bot_id: str) -> Result[list[Friend]]:
"""
获取群信息
"""
- if bots := nonebot.get_bots():
- if bot_id not in bots:
- return Result.warning_("指定Bot未连接...")
- try:
- platform = PlatformUtils.get_platform(bots[bot_id])
- if platform != "qq":
- return Result.warning_("该平台暂不支持该功能...")
- friend_list = await bots[bot_id].get_friend_list()
- for f in friend_list:
- f["ava_url"] = AVA_URL.format(f["user_id"])
- return Result.ok(
- [Friend(**f) for f in friend_list if str(f["user_id"]) != bot_id],
- "拿到了新鲜出炉的数据!",
+ try:
+ bot = nonebot.get_bot(bot_id)
+ friend_list, _ = await PlatformUtils.get_friend_list(bot)
+ result_list = []
+ for f in friend_list:
+ ava_url = AVA_URL.format(f.user_id)
+ result_list.append(
+ Friend(user_id=f.user_id, nickname=f.nickname, ava_url=ava_url)
)
- except Exception as e:
- logger.error("调用API错误", "/get_group_list", e=e)
- return Result.fail(f"{type(e)}: {e}")
- return Result.warning_("无Bot连接...")
+ return Result.ok(
+ result_list,
+ "拿到了新鲜出炉的数据!",
+ )
+ except ValueError:
+ return Result.warning_("指定Bot未连接...")
+ except Exception as e:
+ logger.error("调用API错误", "/get_group_list", e=e)
+ return Result.fail(f"{type(e)}: {e}")
@router.get(
@@ -143,17 +116,21 @@ async def _(bot_id: str) -> Result[list[Friend]]:
description="获取请求数量",
)
async def _() -> Result[dict[str, int]]:
- f_count = await FgRequest.filter(
- request_type=RequestType.FRIEND, handle_type__isnull=True
- ).count()
- g_count = await FgRequest.filter(
- request_type=RequestType.GROUP, handle_type__isnull=True
- ).count()
- data = {
- "friend_count": f_count,
- "group_count": g_count,
- }
- return Result.ok(data, f"{BotConfig.self_nickname}带来了最新的数据!")
+ try:
+ f_count = await FgRequest.filter(
+ request_type=RequestType.FRIEND, handle_type__isnull=True
+ ).count()
+ g_count = await FgRequest.filter(
+ request_type=RequestType.GROUP, handle_type__isnull=True
+ ).count()
+ data = {
+ "friend_count": f_count,
+ "group_count": g_count,
+ }
+ return Result.ok(data, "拿到了新鲜出炉的数据!")
+ except Exception as e:
+ logger.error("调用API错误", "/get_request_count", e=e)
+ return Result.fail(f"{type(e)}: {e}")
@router.get(
@@ -165,43 +142,10 @@ async def _() -> Result[dict[str, int]]:
)
async def _() -> Result[ReqResult]:
try:
- req_result = ReqResult()
- data_list = await FgRequest.filter(handle_type__isnull=True).all()
- for req in data_list:
- if req.request_type == RequestType.FRIEND:
- req_result.friend.append(
- FriendRequestResult(
- oid=req.id,
- bot_id=req.bot_id,
- id=req.user_id,
- flag=req.flag,
- nickname=req.nickname,
- comment=req.comment,
- ava_url=AVA_URL.format(req.user_id),
- type=str(req.request_type).lower(),
- )
- )
- else:
- req_result.group.append(
- GroupRequestResult(
- oid=req.id,
- bot_id=req.bot_id,
- id=req.user_id,
- flag=req.flag,
- nickname=req.nickname,
- comment=req.comment,
- ava_url=GROUP_AVA_URL.format(req.group_id, req.group_id),
- type=str(req.request_type).lower(),
- invite_group=req.group_id,
- group_name=None,
- )
- )
- req_result.friend.reverse()
- req_result.group.reverse()
+ return Result.ok(await ApiDataSource.get_request_list(), "拿到信息啦!")
except Exception as e:
- logger.error("调用API错误", "/get_request", e=e)
- return Result.fail(f"{type(e)}: {e}")
- return Result.ok(req_result, f"{BotConfig.self_nickname}带来了最新的数据!")
+ logger.error(f"{router.prefix}/get_request_list 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.post(
@@ -225,23 +169,21 @@ async def _(cr: ClearRequest) -> Result:
response_class=JSONResponse,
description="拒绝请求",
)
-async def _(parma: HandleRequest) -> Result:
+async def _(param: HandleRequest) -> Result:
try:
- if bots := nonebot.get_bots():
- bot_id = parma.bot_id
- if bot_id not in nonebot.get_bots():
- return Result.warning_("指定Bot未连接...")
- try:
- await FgRequest.refused(bots[bot_id], parma.id)
- except ActionFailed:
- await FgRequest.expire(parma.id)
- return Result.warning_("请求失败,可能该请求已失效或请求数据错误...")
- except NotFoundError:
- return Result.warning_("未找到此Id请求...")
- return Result.ok(info="成功处理了请求!")
- return Result.warning_("无Bot连接...")
+ bot = nonebot.get_bot(param.bot_id)
+ try:
+ await FgRequest.refused(bot, param.id)
+ except ActionFailed:
+ await FgRequest.expire(param.id)
+ return Result.warning_("请求失败,可能该请求已失效或请求数据错误...")
+ except NotFoundError:
+ return Result.warning_("未找到此Id请求...")
+ return Result.ok(info="成功处理了请求!")
+ except ValueError:
+ return Result.warning_("指定Bot未连接...")
except Exception as e:
- logger.error("调用API错误", "/refuse_request", e=e)
+ logger.error(f"{router.prefix}/refuse_request 调用错误", "WebUi", e=e)
return Result.fail(f"{type(e)}: {e}")
@@ -252,8 +194,8 @@ async def _(parma: HandleRequest) -> Result:
response_class=JSONResponse,
description="忽略请求",
)
-async def _(parma: HandleRequest) -> Result:
- await FgRequest.ignore(parma.id)
+async def _(param: HandleRequest) -> Result:
+ await FgRequest.ignore(param.id)
return Result.ok(info="成功处理了请求!")
@@ -264,32 +206,30 @@ async def _(parma: HandleRequest) -> Result:
response_class=JSONResponse,
description="同意请求",
)
-async def _(parma: HandleRequest) -> Result:
+async def _(param: HandleRequest) -> Result:
try:
- if bots := nonebot.get_bots():
- bot_id = parma.bot_id
- if bot_id not in nonebot.get_bots():
- return Result.warning_("指定Bot未连接...")
- if not (req := await FgRequest.get_or_none(id=parma.id)):
- return Result.warning_("未找到此Id请求...")
- if req.request_type == RequestType.GROUP:
- if group := await GroupConsole.get_group(group_id=req.group_id):
- group.group_flag = 1
- await group.save(update_fields=["group_flag"])
- else:
- await GroupConsole.update_or_create(
- group_id=req.group_id,
- defaults={"group_flag": 1},
- )
- try:
- await FgRequest.approve(bots[bot_id], parma.id)
- return Result.ok(info="成功处理了请求!")
- except ActionFailed:
- await FgRequest.expire(parma.id)
- return Result.warning_("请求失败,可能该请求已失效或请求数据错误...")
- return Result.warning_("无Bot连接...")
+ bot = nonebot.get_bot(param.bot_id)
+ if not (req := await FgRequest.get_or_none(id=param.id)):
+ return Result.warning_("未找到此Id请求...")
+ if req.request_type == RequestType.GROUP:
+ if group := await GroupConsole.get_group(group_id=req.group_id):
+ group.group_flag = 1
+ await group.save(update_fields=["group_flag"])
+ else:
+ await GroupConsole.update_or_create(
+ group_id=req.group_id,
+ defaults={"group_flag": 1},
+ )
+ try:
+ await FgRequest.approve(bot, param.id)
+ return Result.ok(info="成功处理了请求!")
+ except ActionFailed:
+ await FgRequest.expire(param.id)
+ return Result.warning_("请求失败,可能该请求已失效或请求数据错误...")
+ except ValueError:
+ return Result.warning_("指定Bot未连接...")
except Exception as e:
- logger.error("调用API错误", "/approve_request", e=e)
+ logger.error(f"{router.prefix}/approve_request 调用错误", "WebUi", e=e)
return Result.fail(f"{type(e)}: {e}")
@@ -302,19 +242,19 @@ async def _(parma: HandleRequest) -> Result:
)
async def _(param: LeaveGroup) -> Result:
try:
- if bots := nonebot.get_bots():
- bot_id = param.bot_id
- platform = PlatformUtils.get_platform(bots[bot_id])
- if platform != "qq":
- return Result.warning_("该平台不支持退群操作...")
- group_list, _ = await PlatformUtils.get_group_list(bots[bot_id])
- if param.group_id not in [g.group_id for g in group_list]:
- return Result.warning_("Bot未在该群聊中...")
- await bots[bot_id].set_group_leave(group_id=param.group_id)
- return Result.ok(info="成功处理了请求!")
- return Result.warning_("无Bot连接...")
+ bot = nonebot.get_bot(param.bot_id)
+ platform = PlatformUtils.get_platform(bot)
+ if platform != "qq":
+ return Result.warning_("该平台不支持退群操作...")
+ group_list, _ = await PlatformUtils.get_group_list(bot)
+ if param.group_id not in [g.group_id for g in group_list]:
+ return Result.warning_("Bot未在该群聊中...")
+ await bot.set_group_leave(group_id=param.group_id)
+ return Result.ok(info="成功处理了请求!")
+ except ValueError:
+ return Result.warning_("指定Bot未连接...")
except Exception as e:
- logger.error("调用API错误", "/leave_group", e=e)
+ logger.error(f"{router.prefix}/leave_group 调用错误", "WebUi", e=e)
return Result.fail(f"{type(e)}: {e}")
@@ -327,19 +267,19 @@ async def _(param: LeaveGroup) -> Result:
)
async def _(param: DeleteFriend) -> Result:
try:
- if bots := nonebot.get_bots():
- bot_id = param.bot_id
- platform = PlatformUtils.get_platform(bots[bot_id])
- if platform != "qq":
- return Result.warning_("该平台不支持删除好友操作...")
- friend_list = await bots[bot_id].get_friend_list()
- if param.user_id not in [str(g["user_id"]) for g in friend_list]:
- return Result.warning_("Bot未有其好友...")
- await bots[bot_id].delete_friend(user_id=param.user_id)
- return Result.ok(info="成功处理了请求!")
- return Result.warning_("Bot未连接...")
+ bot = nonebot.get_bot(param.bot_id)
+ platform = PlatformUtils.get_platform(bot)
+ if platform != "qq":
+ return Result.warning_("该平台不支持删除好友操作...")
+ friend_list, _ = await PlatformUtils.get_friend_list(bot)
+ if param.user_id not in [f.user_id for f in friend_list]:
+ return Result.warning_("Bot未有其好友...")
+ await bot.delete_friend(user_id=param.user_id)
+ return Result.ok(info="成功处理了请求!")
+ except ValueError:
+ return Result.warning_("指定Bot未连接...")
except Exception as e:
- logger.error("调用API错误", "/delete_friend", e=e)
+ logger.error(f"{router.prefix}/delete_friend 调用错误", "WebUi", e=e)
return Result.fail(f"{type(e)}: {e}")
@@ -351,43 +291,18 @@ async def _(param: DeleteFriend) -> Result:
description="获取好友详情",
)
async def _(bot_id: str, user_id: str) -> Result[UserDetail]:
- if bots := nonebot.get_bots():
- if bot_id in bots:
- if fd := [
- x
- for x in await bots[bot_id].get_friend_list()
- if str(x["user_id"]) == user_id
- ]:
- like_plugin_list = (
- await Statistics.filter(user_id=user_id)
- .annotate(count=Count("id"))
- .group_by("plugin_name")
- .order_by("-count")
- .limit(5)
- .values_list("plugin_name", "count")
- )
- like_plugin = {}
- module_list = [x[0] for x in like_plugin_list]
- plugins = await PluginInfo.filter(module__in=module_list).all()
- module2name = {p.module: p.name for p in plugins}
- for data in like_plugin_list:
- name = module2name.get(data[0]) or data[0]
- like_plugin[name] = data[1]
- user = fd[0]
- user_detail = UserDetail(
- user_id=user_id,
- ava_url=AVA_URL.format(user_id),
- nickname=user["nickname"],
- remark=user["remark"],
- is_ban=await BanConsole.is_ban(user_id),
- chat_count=await ChatHistory.filter(user_id=user_id).count(),
- call_count=await Statistics.filter(user_id=user_id).count(),
- like_plugin=like_plugin,
- )
- return Result.ok(user_detail)
- else:
- return Result.warning_("未添加指定好友...")
- return Result.warning_("无Bot连接...")
+ try:
+ result = await ApiDataSource.get_friend_detail(bot_id, user_id)
+ return (
+ Result.ok(result, "拿到信息啦!")
+ if result
+ else Result.warning_("未找到该好友...")
+ )
+ except ValueError:
+ return Result.warning_("指定Bot未连接...")
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_friend_detail 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.get(
@@ -397,90 +312,12 @@ async def _(bot_id: str, user_id: str) -> Result[UserDetail]:
response_class=JSONResponse,
description="获取群组详情",
)
-async def _(bot_id: str, group_id: str) -> Result[GroupDetail]:
- if not (bots := nonebot.get_bots()):
- return Result.warning_("无Bot连接...")
- if bot_id not in bots:
- return Result.warning_("未添加指定群组...")
- group = await GroupConsole.get_or_none(group_id=group_id)
- if not group:
- return Result.warning_("指定群组未被收录...")
- like_plugin_list = (
- await Statistics.filter(group_id=group_id)
- .annotate(count=Count("id"))
- .group_by("plugin_name")
- .order_by("-count")
- .limit(5)
- .values_list("plugin_name", "count")
- )
- like_plugin = {}
- plugins = await PluginInfo.get_plugins()
- module2name = {p.module: p.name for p in plugins}
- for data in like_plugin_list:
- name = module2name.get(data[0]) or data[0]
- like_plugin[name] = data[1]
- close_plugins: list[Plugin] = []
- if group.block_plugin:
- for module in group.block_plugin.replace("<", "").split(","):
- if module:
- plugin = Plugin(
- module=module,
- plugin_name=module,
- is_super_block=False,
- )
- plugin.plugin_name = module2name.get(module) or module
- close_plugins.append(plugin)
- exists_modules = [p.module for p in close_plugins]
- if group.superuser_block_plugin:
- for module in group.superuser_block_plugin.replace("<", "").split(","):
- if module and module not in exists_modules:
- plugin = Plugin(
- module=module,
- plugin_name=module,
- is_super_block=True,
- )
- plugin.plugin_name = module2name.get(module) or module
- close_plugins.append(plugin)
- all_task = await TaskInfo.annotate().values_list("module", "name")
- task_module2name = {x[0]: x[1] for x in all_task}
- task_list = []
- if group.block_task or group.superuser_block_plugin:
- sbp = group.superuser_block_plugin.replace("<", "").split(",")
- split_task = group.block_task.replace("<", "").split(",")
- for task in all_task:
- task_list.append(
- Task(
- name=task[0],
- zh_name=task_module2name.get(task[0]) or task[0],
- status=task[0] not in split_task and task[0] not in sbp,
- is_super_block=task[0] in sbp,
- )
- )
- else:
- for task in all_task:
- task_list.append(
- Task(
- name=task[0],
- zh_name=task_module2name.get(task[0]) or task[0],
- status=True,
- is_super_block=False,
- )
- )
- group_detail = GroupDetail(
- group_id=group_id,
- ava_url=GROUP_AVA_URL.format(group_id, group_id),
- name=group.group_name,
- member_count=group.member_count,
- max_member_count=group.max_member_count,
- chat_count=await ChatHistory.filter(group_id=group_id).count(),
- call_count=await Statistics.filter(group_id=group_id).count(),
- like_plugin=like_plugin,
- level=group.level,
- status=group.status,
- close_plugins=close_plugins,
- task=task_list,
- )
- return Result.ok(group_detail)
+async def _(group_id: str) -> Result[GroupDetail]:
+ try:
+ return Result.ok(await ApiDataSource.get_group_detail(group_id), "拿到信息啦!")
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_group_detail 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.post(
@@ -488,25 +325,17 @@ async def _(bot_id: str, group_id: str) -> Result[GroupDetail]:
dependencies=[authentication()],
response_model=Result,
response_class=JSONResponse,
- description="获取群组详情",
+ description="发送消息",
)
-async def _(param: SendMessage) -> Result:
- if not (bots := nonebot.get_bots()):
- return Result.warning_("无Bot连接...")
- if param.bot_id in bots:
- platform = PlatformUtils.get_platform(bots[param.bot_id])
- if platform != "qq":
- return Result.warning_("暂不支持该平台...")
- try:
- if param.user_id:
- await bots[param.bot_id].send_private_msg(
- user_id=str(param.user_id), message=param.message
- )
- else:
- await bots[param.bot_id].send_group_msg(
- group_id=str(param.group_id), message=param.message
- )
- except Exception as e:
- return Result.fail(str(e))
+async def _(param: SendMessageParam) -> Result:
+ try:
+ bot = nonebot.get_bot(param.bot_id)
+ await PlatformUtils.send_message(
+ bot, param.user_id, param.group_id, param.message
+ )
return Result.ok("发送成功!")
- return Result.warning_("指定Bot未连接...")
+ except ValueError:
+ return Result.warning_("指定Bot未连接...")
+ except Exception as e:
+ logger.error(f"{router.prefix}/send_message 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
diff --git a/zhenxun/builtin_plugins/web_ui/api/tabs/manage/chat.py b/zhenxun/builtin_plugins/web_ui/api/tabs/manage/chat.py
index 164e260b..62b2f959 100644
--- a/zhenxun/builtin_plugins/web_ui/api/tabs/manage/chat.py
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/manage/chat.py
@@ -3,7 +3,7 @@ import nonebot
from nonebot import on_message
from nonebot.adapters.onebot.v11 import MessageEvent
from nonebot_plugin_alconna import At, Hyper, Image, Text, UniMsg
-from nonebot_plugin_session import EventSession
+from nonebot_plugin_uninfo import Uninfo
from starlette.websockets import WebSocket, WebSocketDisconnect, WebSocketState
from zhenxun.models.group_member_info import GroupInfoUser
@@ -28,7 +28,7 @@ matcher = on_message(block=False, priority=1, rule=lambda: bool(ws_conn))
@driver.on_shutdown
async def _():
- if ws_conn:
+ if ws_conn and ws_conn.client_state == WebSocketState.CONNECTED:
await ws_conn.close()
@@ -36,7 +36,7 @@ async def _():
async def _(websocket: WebSocket):
global ws_conn
await websocket.accept()
- if not ws_conn:
+ if not ws_conn or ws_conn.client_state != WebSocketState.CONNECTED:
ws_conn = websocket
try:
while websocket.client_state == WebSocketState.CONNECTED:
@@ -80,25 +80,24 @@ async def message_handle(
@matcher.handle()
async def _(
- message: UniMsg, event: MessageEvent, session: EventSession, uname: str = UserName()
+ message: UniMsg, event: MessageEvent, session: Uninfo, uname: str = UserName()
):
global ws_conn, ID2NAME, ID_LIST
- uid = session.id1
- if ws_conn and ws_conn.client_state == WebSocketState.CONNECTED and uid:
+ if ws_conn and ws_conn.client_state == WebSocketState.CONNECTED:
msg_id = event.message_id
if msg_id in ID_LIST:
return
ID_LIST.append(msg_id)
if len(ID_LIST) > 50:
ID_LIST = ID_LIST[40:]
- gid = session.id3 or session.id2
+ gid = session.group.id if session.group else None
messages = await message_handle(message, gid)
data = Message(
- object_id=gid or uid,
- user_id=uid,
+ object_id=gid or session.user.id,
+ user_id=session.user.id,
group_id=gid,
message=messages,
name=uname,
- ava_url=AVA_URL.format(uid),
+ ava_url=AVA_URL.format(session.user.id),
)
await ws_conn.send_json(data.dict())
diff --git a/zhenxun/builtin_plugins/web_ui/api/tabs/manage/data_source.py b/zhenxun/builtin_plugins/web_ui/api/tabs/manage/data_source.py
new file mode 100644
index 00000000..f573fb5b
--- /dev/null
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/manage/data_source.py
@@ -0,0 +1,274 @@
+import nonebot
+from tortoise.functions import Count
+
+from zhenxun.models.ban_console import BanConsole
+from zhenxun.models.chat_history import ChatHistory
+from zhenxun.models.fg_request import FgRequest
+from zhenxun.models.group_console import GroupConsole
+from zhenxun.models.plugin_info import PluginInfo
+from zhenxun.models.statistics import Statistics
+from zhenxun.models.task_info import TaskInfo
+from zhenxun.utils.common_utils import CommonUtils
+from zhenxun.utils.enum import RequestType
+from zhenxun.utils.platform import PlatformUtils
+
+from ....config import AVA_URL, GROUP_AVA_URL
+from .model import (
+ FriendRequestResult,
+ GroupDetail,
+ GroupRequestResult,
+ Plugin,
+ ReqResult,
+ Task,
+ UpdateGroup,
+ UserDetail,
+)
+
+
+class ApiDataSource:
+ @classmethod
+ async def update_group(cls, group: UpdateGroup):
+ """更新群组数据
+
+ 参数:
+ group: UpdateGroup
+ """
+ db_group = await GroupConsole.get_group(group.group_id) or GroupConsole(
+ group_id=group.group_id
+ )
+ task_list = await TaskInfo.all().values_list("module", flat=True)
+ db_group.level = group.level
+ db_group.status = group.status
+ if group.close_plugins:
+ db_group.block_plugin = CommonUtils.convert_module_format(
+ group.close_plugins
+ )
+ else:
+ db_group.block_plugin = ""
+ if group.task:
+ if block_task := [t for t in task_list if t not in group.task]:
+ db_group.block_task = CommonUtils.convert_module_format(block_task) # type: ignore
+ else:
+ db_group.block_task = CommonUtils.convert_module_format(task_list) # type: ignore
+ await db_group.save()
+
+ @classmethod
+ async def get_request_list(cls) -> ReqResult:
+ """获取好友与群组请求列表
+
+ 返回:
+ ReqResult: 数据内容
+ """
+ req_result = ReqResult()
+ data_list = await FgRequest.filter(handle_type__isnull=True).all()
+ for req in data_list:
+ if req.request_type == RequestType.FRIEND:
+ req_result.friend.append(
+ FriendRequestResult(
+ oid=req.id,
+ bot_id=req.bot_id,
+ id=req.user_id,
+ flag=req.flag,
+ nickname=req.nickname,
+ comment=req.comment,
+ ava_url=AVA_URL.format(req.user_id),
+ type=str(req.request_type).lower(),
+ )
+ )
+ else:
+ req_result.group.append(
+ GroupRequestResult(
+ oid=req.id,
+ bot_id=req.bot_id,
+ id=req.user_id,
+ flag=req.flag,
+ nickname=req.nickname,
+ comment=req.comment,
+ ava_url=GROUP_AVA_URL.format(req.group_id, req.group_id),
+ type=str(req.request_type).lower(),
+ invite_group=req.group_id,
+ group_name=None,
+ )
+ )
+ req_result.friend.reverse()
+ req_result.group.reverse()
+ return req_result
+
+ @classmethod
+ async def get_friend_detail(cls, bot_id: str, user_id: str) -> UserDetail | None:
+ """获取好友详情
+
+ 参数:
+ bot_id: bot id
+ user_id: 用户id
+
+ 返回:
+ UserDetail | None: 详情数据
+ """
+ bot = nonebot.get_bot(bot_id)
+ friend_list, _ = await PlatformUtils.get_friend_list(bot)
+ fd = [x for x in friend_list if x == user_id]
+ if not fd:
+ return None
+ like_plugin_list = (
+ await Statistics.filter(user_id=user_id)
+ .annotate(count=Count("id"))
+ .group_by("plugin_name")
+ .order_by("-count")
+ .limit(5)
+ .values_list("plugin_name", "count")
+ )
+ like_plugin = {}
+ module_list = [x[0] for x in like_plugin_list]
+ plugins = await PluginInfo.filter(module__in=module_list).all()
+ module2name = {p.module: p.name for p in plugins}
+ for data in like_plugin_list:
+ name = module2name.get(data[0]) or data[0]
+ like_plugin[name] = data[1]
+ user = fd[0]
+ return UserDetail(
+ user_id=user_id,
+ ava_url=AVA_URL.format(user_id),
+ nickname=user.user_name,
+ remark="",
+ is_ban=await BanConsole.is_ban(user_id),
+ chat_count=await ChatHistory.filter(user_id=user_id).count(),
+ call_count=await Statistics.filter(user_id=user_id).count(),
+ like_plugin=like_plugin,
+ )
+
+ @classmethod
+ async def __get_group_detail_like_plugin(cls, group_id: str) -> dict[str, int]:
+ """获取群组喜爱的插件
+
+ 参数:
+ group_id: 群组id
+
+ 返回:
+ dict[str, int]: 插件与调用次数
+ """
+ like_plugin_list = (
+ await Statistics.filter(group_id=group_id)
+ .annotate(count=Count("id"))
+ .group_by("plugin_name")
+ .order_by("-count")
+ .limit(5)
+ .values_list("plugin_name", "count")
+ )
+ like_plugin = {}
+ plugins = await PluginInfo.get_plugins()
+ module2name = {p.module: p.name for p in plugins}
+ for data in like_plugin_list:
+ name = module2name.get(data[0]) or data[0]
+ like_plugin[name] = data[1]
+ return like_plugin
+
+ @classmethod
+ async def __get_group_detail_disable_plugin(
+ cls, group: GroupConsole
+ ) -> list[Plugin]:
+ """获取群组禁用插件
+
+ 参数:
+ group: GroupConsole
+
+ 返回:
+ list[Plugin]: 禁用插件数据列表
+ """
+ disable_plugins: list[Plugin] = []
+ plugins = await PluginInfo.get_plugins()
+ module2name = {p.module: p.name for p in plugins}
+ if group.block_plugin:
+ for module in CommonUtils.convert_module_format(group.block_plugin):
+ if module:
+ plugin = Plugin(
+ module=module,
+ plugin_name=module,
+ is_super_block=False,
+ )
+ plugin.plugin_name = module2name.get(module) or module
+ disable_plugins.append(plugin)
+ exists_modules = [p.module for p in disable_plugins]
+ if group.superuser_block_plugin:
+ for module in CommonUtils.convert_module_format(
+ group.superuser_block_plugin
+ ):
+ if module and module not in exists_modules:
+ plugin = Plugin(
+ module=module,
+ plugin_name=module,
+ is_super_block=True,
+ )
+ plugin.plugin_name = module2name.get(module) or module
+ disable_plugins.append(plugin)
+ return disable_plugins
+
+ @classmethod
+ async def __get_group_detail_task(cls, group: GroupConsole) -> list[Task]:
+ """获取群组被动技能状态
+
+ 参数:
+ group: GroupConsole
+
+ 返回:
+ list[Task]: 群组被动列表
+ """
+ all_task = await TaskInfo.annotate().values_list("module", "name")
+ task_module2name = {x[0]: x[1] for x in all_task}
+ task_list = []
+ if group.block_task or group.superuser_block_plugin:
+ sbp = CommonUtils.convert_module_format(group.superuser_block_task)
+ tasks = CommonUtils.convert_module_format(group.block_task)
+ task_list.extend(
+ Task(
+ name=task[0],
+ zh_name=task_module2name.get(task[0]) or task[0],
+ status=task[0] not in tasks and task[0] not in sbp,
+ is_super_block=task[0] in sbp,
+ )
+ for task in all_task
+ )
+ else:
+ task_list.extend(
+ Task(
+ name=task[0],
+ zh_name=task_module2name.get(task[0]) or task[0],
+ status=True,
+ is_super_block=False,
+ )
+ for task in all_task
+ )
+ return task_list
+
+ @classmethod
+ async def get_group_detail(cls, group_id: str) -> GroupDetail | None:
+ """获取群组详情
+
+ 参数:
+ group_id: 群组id
+
+ 返回:
+ GroupDetail | None: 群组详情数据
+ """
+ group = await GroupConsole.get_or_none(group_id=group_id)
+ if not group:
+ return None
+ like_plugin = await cls.__get_group_detail_like_plugin(group_id)
+ disable_plugins: list[Plugin] = await cls.__get_group_detail_disable_plugin(
+ group
+ )
+ task_list = await cls.__get_group_detail_task(group)
+ return GroupDetail(
+ group_id=group_id,
+ ava_url=GROUP_AVA_URL.format(group_id, group_id),
+ name=group.group_name,
+ member_count=group.member_count,
+ max_member_count=group.max_member_count,
+ chat_count=await ChatHistory.filter(group_id=group_id).count(),
+ call_count=await Statistics.filter(group_id=group_id).count(),
+ like_plugin=like_plugin,
+ level=group.level,
+ status=group.status,
+ close_plugins=disable_plugins,
+ task=task_list,
+ )
diff --git a/zhenxun/builtin_plugins/web_ui/api/tabs/manage/model.py b/zhenxun/builtin_plugins/web_ui/api/tabs/manage/model.py
index 60833870..9f5d9fd4 100644
--- a/zhenxun/builtin_plugins/web_ui/api/tabs/manage/model.py
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/manage/model.py
@@ -257,7 +257,7 @@ class Message(BaseModel):
"""用户头像"""
-class SendMessage(BaseModel):
+class SendMessageParam(BaseModel):
"""
发送消息
"""
diff --git a/zhenxun/builtin_plugins/web_ui/api/tabs/plugin_manage/__init__.py b/zhenxun/builtin_plugins/web_ui/api/tabs/plugin_manage/__init__.py
index ebadeb9b..02d87261 100644
--- a/zhenxun/builtin_plugins/web_ui/api/tabs/plugin_manage/__init__.py
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/plugin_manage/__init__.py
@@ -11,6 +11,7 @@ from zhenxun.utils.enum import BlockType, PluginType
from ....base_model import Result
from ....utils import authentication
+from .data_source import ApiDataSource
from .model import (
PluginConfig,
PluginCount,
@@ -34,31 +35,12 @@ async def _(
plugin_type: list[PluginType] = Query(None), menu_type: str | None = None
) -> Result[list[PluginInfo]]:
try:
- plugin_list: list[PluginInfo] = []
- query = DbPluginInfo
- if plugin_type:
- query = query.filter(plugin_type__in=plugin_type, load_status=True)
- if menu_type:
- query = query.filter(menu_type=menu_type, load_status=True)
- plugins = await query.all()
- for plugin in plugins:
- plugin_info = PluginInfo(
- module=plugin.module,
- plugin_name=plugin.name,
- default_status=plugin.default_status,
- limit_superuser=plugin.limit_superuser,
- cost_gold=plugin.cost_gold,
- menu_type=plugin.menu_type,
- version=plugin.version or "0",
- level=plugin.level,
- status=plugin.status,
- author=plugin.author,
- )
- plugin_list.append(plugin_info)
+ return Result.ok(
+ await ApiDataSource.get_plugin_list(plugin_type, menu_type), "拿到信息啦!"
+ )
except Exception as e:
- logger.error("调用API错误", "/get_plugins", e=e)
- return Result.fail(f"{type(e)}: {e}")
- return Result.ok(plugin_list, "拿到了新鲜出炉的数据!")
+ logger.error(f"{router.prefix}/get_plugin_list 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.get(
@@ -69,21 +51,26 @@ async def _(
deprecated="获取插件数量", # type: ignore
)
async def _() -> Result[int]:
- plugin_count = PluginCount()
- plugin_count.normal = await DbPluginInfo.filter(
- plugin_type=PluginType.NORMAL, load_status=True
- ).count()
- plugin_count.admin = await DbPluginInfo.filter(
- plugin_type__in=[PluginType.ADMIN, PluginType.SUPER_AND_ADMIN], load_status=True
- ).count()
- plugin_count.superuser = await DbPluginInfo.filter(
- plugin_type__in=[PluginType.SUPERUSER, PluginType.SUPER_AND_ADMIN],
- load_status=True,
- ).count()
- plugin_count.other = await DbPluginInfo.filter(
- plugin_type__in=[PluginType.HIDDEN, PluginType.DEPENDANT], load_status=True
- ).count()
- return Result.ok(plugin_count)
+ try:
+ plugin_count = PluginCount()
+ plugin_count.normal = await DbPluginInfo.filter(
+ plugin_type=PluginType.NORMAL, load_status=True
+ ).count()
+ plugin_count.admin = await DbPluginInfo.filter(
+ plugin_type__in=[PluginType.ADMIN, PluginType.SUPER_AND_ADMIN],
+ load_status=True,
+ ).count()
+ plugin_count.superuser = await DbPluginInfo.filter(
+ plugin_type__in=[PluginType.SUPERUSER, PluginType.SUPER_AND_ADMIN],
+ load_status=True,
+ ).count()
+ plugin_count.other = await DbPluginInfo.filter(
+ plugin_type__in=[PluginType.HIDDEN, PluginType.DEPENDANT], load_status=True
+ ).count()
+ return Result.ok(plugin_count, "拿到信息啦!")
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_plugin_count 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
@router.post(
@@ -93,34 +80,15 @@ async def _() -> Result[int]:
response_class=JSONResponse,
description="更新插件参数",
)
-async def _(plugin: UpdatePlugin) -> Result:
+async def _(param: UpdatePlugin) -> Result:
try:
- db_plugin = await DbPluginInfo.get_or_none(
- module=plugin.module, load_status=True
- )
- if not db_plugin:
- return Result.fail("插件不存在...")
- db_plugin.default_status = plugin.default_status
- db_plugin.limit_superuser = plugin.limit_superuser
- db_plugin.cost_gold = plugin.cost_gold
- db_plugin.level = plugin.level
- db_plugin.menu_type = plugin.menu_type
- db_plugin.block_type = plugin.block_type
- db_plugin.status = plugin.block_type != BlockType.ALL
- await db_plugin.save()
- # 配置项
- if plugin.configs and (configs := Config.get(plugin.module)):
- for key in plugin.configs:
- if c := configs.configs.get(key):
- value = plugin.configs[key]
- if c.type and value is not None:
- value = cattrs.structure(value, c.type)
- Config.set_config(plugin.module, key, value)
- Config.save(save_simple_data=True)
+ await ApiDataSource.update_plugin(param)
+ return Result.ok(info="已经帮你写好啦!")
+ except ValueError:
+ return Result.fail("插件数据不存在...")
except Exception as e:
- logger.error("调用API错误", "/update_plugins", e=e)
+ logger.error(f"{router.prefix}/update_plugin 调用错误", "WebUi", e=e)
return Result.fail(f"{type(e)}: {e}")
- return Result.ok(info="已经帮你写好啦!")
@router.post(
@@ -131,17 +99,21 @@ async def _(plugin: UpdatePlugin) -> Result:
description="开关插件",
)
async def _(param: PluginSwitch) -> Result:
- db_plugin = await DbPluginInfo.get_or_none(module=param.module, load_status=True)
- if not db_plugin:
- return Result.fail("插件不存在...")
- if not param.status:
- db_plugin.block_type = BlockType.ALL
- db_plugin.status = False
- else:
- db_plugin.block_type = None
- db_plugin.status = True
- await db_plugin.save()
- return Result.ok(info="成功改变了开关状态!")
+ try:
+ db_plugin = await DbPluginInfo.get_plugin(module=param.module)
+ if not db_plugin:
+ return Result.fail("插件不存在...")
+ if not param.status:
+ db_plugin.block_type = BlockType.ALL
+ db_plugin.status = False
+ else:
+ db_plugin.block_type = None
+ db_plugin.status = True
+ await db_plugin.save()
+ return Result.ok(info="成功改变了开关状态!")
+ except Exception as e:
+ logger.error(f"{router.prefix}/change_switch 调用错误", "WebUi", e=e)
+ return Result.fail(f"{type(e)}: {e}")
@router.get(
@@ -152,16 +124,20 @@ async def _(param: PluginSwitch) -> Result:
description="获取插件类型",
)
async def _() -> Result[list[str]]:
- menu_type_list = []
- result = (
- await DbPluginInfo.filter(load_status=True)
- .annotate()
- .values_list("menu_type", flat=True)
- )
- for r in result:
- if r not in menu_type_list and r:
- menu_type_list.append(r)
- return Result.ok(menu_type_list)
+ try:
+ menu_type_list = []
+ result = (
+ await DbPluginInfo.filter(load_status=True)
+ .annotate()
+ .values_list("menu_type", flat=True)
+ )
+ for r in result:
+ if r not in menu_type_list and r:
+ menu_type_list.append(r)
+ return Result.ok(menu_type_list)
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_plugin_menu_type 调用错误", "WebUi", e=e)
+ return Result.fail(f"{type(e)}: {e}")
@router.get(
@@ -172,46 +148,12 @@ async def _() -> Result[list[str]]:
description="获取插件详情",
)
async def _(module: str) -> Result[PluginDetail]:
- db_plugin = await DbPluginInfo.get_or_none(module=module, load_status=True)
- if not db_plugin:
- return Result.fail("插件不存在...")
- config_list = []
- if config := Config.get(module):
- for cfg in config.configs:
- type_str = ""
- type_inner = None
- if r := re.search(r"", str(config.configs[cfg].type)):
- type_str = r[1]
- elif r := re.search(r"typing\.(.*)\[(.*)\]", str(config.configs[cfg].type)):
- type_str = r[1]
- if type_str:
- type_str = type_str.lower()
- type_inner = r[2]
- if type_inner:
- type_inner = [x.strip() for x in type_inner.split(",")]
- config_list.append(
- PluginConfig(
- module=module,
- key=cfg,
- value=config.configs[cfg].value,
- help=config.configs[cfg].help,
- default_value=config.configs[cfg].default_value,
- type=type_str,
- type_inner=type_inner, # type: ignore
- )
- )
- plugin_info = PluginDetail(
- module=module,
- plugin_name=db_plugin.name,
- default_status=db_plugin.default_status,
- limit_superuser=db_plugin.limit_superuser,
- cost_gold=db_plugin.cost_gold,
- menu_type=db_plugin.menu_type,
- version=db_plugin.version or "0",
- level=db_plugin.level,
- status=db_plugin.status,
- author=db_plugin.author,
- config_list=config_list,
- block_type=db_plugin.block_type,
- )
- return Result.ok(plugin_info)
+ try:
+ return Result.ok(
+ await ApiDataSource.get_plugin_detail(module), "已经帮你写好啦!"
+ )
+ except ValueError:
+ return Result.fail("插件数据不存在...")
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_plugin 调用错误", "WebUi", e=e)
+ return Result.fail(f"{type(e)}: {e}")
diff --git a/zhenxun/builtin_plugins/web_ui/api/tabs/plugin_manage/data_source.py b/zhenxun/builtin_plugins/web_ui/api/tabs/plugin_manage/data_source.py
new file mode 100644
index 00000000..f6c5e86c
--- /dev/null
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/plugin_manage/data_source.py
@@ -0,0 +1,153 @@
+import re
+
+import cattrs
+from fastapi import Query
+
+from zhenxun.configs.config import Config
+from zhenxun.configs.utils import ConfigGroup
+from zhenxun.models.plugin_info import PluginInfo
+from zhenxun.models.plugin_info import PluginInfo as DbPluginInfo
+from zhenxun.utils.enum import BlockType, PluginType
+
+from .model import PluginConfig, PluginDetail, UpdatePlugin
+
+
+class ApiDataSource:
+ @classmethod
+ async def get_plugin_list(
+ cls, plugin_type: list[PluginType] = Query(None), menu_type: str | None = None
+ ) -> list[PluginInfo]:
+ """获取插件列表
+
+ 参数:
+ plugin_type: 插件类型.
+ menu_type: 菜单类型.
+
+ 返回:
+ list[PluginInfo]: 插件数据列表
+ """
+ plugin_list: list[PluginInfo] = []
+ query = DbPluginInfo
+ if plugin_type:
+ query = query.filter(plugin_type__in=plugin_type, load_status=True)
+ if menu_type:
+ query = query.filter(menu_type=menu_type, load_status=True)
+ plugins = await query.all()
+ for plugin in plugins:
+ plugin_info = PluginInfo(
+ module=plugin.module,
+ plugin_name=plugin.name,
+ default_status=plugin.default_status,
+ limit_superuser=plugin.limit_superuser,
+ cost_gold=plugin.cost_gold,
+ menu_type=plugin.menu_type,
+ version=plugin.version or "0",
+ level=plugin.level,
+ status=plugin.status,
+ author=plugin.author,
+ )
+ plugin_list.append(plugin_info)
+ return plugin_list
+
+ @classmethod
+ async def update_plugin(cls, param: UpdatePlugin) -> DbPluginInfo:
+ """更新插件数据
+
+ 参数:
+ param: UpdatePlugin
+
+ 返回:
+ DbPluginInfo | None: 插件数据
+ """
+ db_plugin = await DbPluginInfo.get_plugin(module=param.module)
+ if not db_plugin:
+ raise ValueError("插件不存在")
+ db_plugin.default_status = param.default_status
+ db_plugin.limit_superuser = param.limit_superuser
+ db_plugin.cost_gold = param.cost_gold
+ db_plugin.level = param.level
+ db_plugin.menu_type = param.menu_type
+ db_plugin.block_type = param.block_type
+ db_plugin.status = param.block_type != BlockType.ALL
+ await db_plugin.save()
+ # 配置项
+ if param.configs and (configs := Config.get(param.module)):
+ for key in param.configs:
+ if c := configs.configs.get(key):
+ value = param.configs[key]
+ if c.type and value is not None:
+ value = cattrs.structure(value, c.type)
+ Config.set_config(param.module, key, value)
+ Config.save(save_simple_data=True)
+ return db_plugin
+
+ @classmethod
+ def __build_plugin_config(
+ cls, module: str, cfg: str, config: ConfigGroup
+ ) -> PluginConfig:
+ """获取插件配置项
+
+ 参数:
+ module: 模块名
+ cfg: cfg
+ config: ConfigGroup
+
+ 返回:
+ lPluginConfig: 配置数据
+ """
+ type_str = ""
+ type_inner = None
+ if r := re.search(r"", str(config.configs[cfg].type)):
+ type_str = r[1]
+ elif r := re.search(r"typing\.(.*)\[(.*)\]", str(config.configs[cfg].type)):
+ type_str = r[1]
+ if type_str:
+ type_str = type_str.lower()
+ type_inner = r[2]
+ if type_inner:
+ type_inner = [x.strip() for x in type_inner.split(",")]
+ return PluginConfig(
+ module=module,
+ key=cfg,
+ value=config.configs[cfg].value,
+ help=config.configs[cfg].help,
+ default_value=config.configs[cfg].default_value,
+ type=type_str,
+ type_inner=type_inner, # type: ignore
+ )
+
+ @classmethod
+ async def get_plugin_detail(cls, module: str) -> PluginDetail:
+ """获取插件详情
+
+ 参数:
+ module: 模块名
+
+ 异常:
+ ValueError: 插件不存在
+
+ 返回:
+ PluginDetail: 插件详情数据
+ """
+ db_plugin = await DbPluginInfo.get_plugin(module=module)
+ if not db_plugin:
+ raise ValueError("插件不存在")
+ config_list = []
+ if config := Config.get(module):
+ config_list.extend(
+ cls.__build_plugin_config(module, cfg, config) for cfg in config.configs
+ )
+ return PluginDetail(
+ module=module,
+ plugin_name=db_plugin.name,
+ default_status=db_plugin.default_status,
+ limit_superuser=db_plugin.limit_superuser,
+ cost_gold=db_plugin.cost_gold,
+ menu_type=db_plugin.menu_type,
+ version=db_plugin.version or "0",
+ level=db_plugin.level,
+ status=db_plugin.status,
+ author=db_plugin.author,
+ config_list=config_list,
+ block_type=db_plugin.block_type,
+ )
diff --git a/zhenxun/services/__init__.py b/zhenxun/services/__init__.py
index e69de29b..5727da7d 100644
--- a/zhenxun/services/__init__.py
+++ b/zhenxun/services/__init__.py
@@ -0,0 +1,8 @@
+from nonebot import require
+
+require("nonebot_plugin_apscheduler")
+require("nonebot_plugin_alconna")
+require("nonebot_plugin_session")
+require("nonebot_plugin_userinfo")
+require("nonebot_plugin_htmlrender")
+require("nonebot_plugin_uninfo")
diff --git a/zhenxun/utils/platform.py b/zhenxun/utils/platform.py
index f53fe900..459d2a2a 100644
--- a/zhenxun/utils/platform.py
+++ b/zhenxun/utils/platform.py
@@ -268,7 +268,7 @@ class PlatformUtils:
返回:
Receipt | None: 是否发送成功
"""
- if target := cls.get_target(bot, user_id, group_id):
+ if target := cls.get_target(user_id=user_id, group_id=group_id):
send_message = (
MessageUtils.build_message(message)
if isinstance(message, str)
@@ -425,7 +425,7 @@ class PlatformUtils:
@classmethod
def get_target(
cls,
- bot: Bot,
+ *,
user_id: str | None = None,
group_id: str | None = None,
channel_id: str | None = None,
@@ -530,7 +530,9 @@ async def broadcast_group(
)
continue
target = PlatformUtils.get_target(
- _bot, None, group.group_id, group.channel_id
+ user_id=None,
+ group_id=group.group_id,
+ channel_id=group.channel_id,
)
if target:
_used_group.append(key)