重构webui适配 (#1801)

* ♻️ 使用Uninfo重构PlatformUtils基础方法

* 🩹 优化插件加载与模块格式转换逻辑

* 🚑 修复商店道具无法使用

* 🚑 修复道具无法正常使用

* 🔧 增加Bot状态管理及模块禁用功能

* 🎨  优化Web UI代码结构,修改target方法

* 🚨 auto fix by pre-commit hooks

* 🎨 添加菜单API及优化异常处理

* 🐛 优化菜单API及模型结构,修复WebUi插件列表Api

* 📝 更新仓库readme

* 🚨 add mdlint file

* 📝 Add help chapter.

* 🐛 修复优化AuthChecker逻辑

* 🐛 优化数据库API,移除冗余导入及修正SQL_DICT引用

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: BalconyJH <balconyjh@gmail.com>
This commit is contained in:
HibiKier
2024-12-25 12:03:49 +08:00
committed by GitHub
co-authored by pre-commit-ci[bot] BalconyJH
parent ebf05fd884
commit 35014e4048
32 changed files with 1939 additions and 1754 deletions
@@ -3,14 +3,15 @@ from fastapi.responses import JSONResponse
import nonebot
from nonebot.drivers import Driver
from tortoise import Tortoise
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 +21,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 +28,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 +36,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 +55,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 +73,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 +101,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 +115,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(
@@ -197,5 +140,5 @@ async def _(query: QueryModel) -> Result[BaseResultModel]:
)
async def _(plugin_name: str | None = None) -> Result[dict]:
if plugin_name:
return Result.ok(SQL_DICT.get(plugin_name))
return Result.ok(str(SQL_DICT))
return Result.ok(ApiDataSource.SQL_DICT.get(plugin_name))
return Result.ok(str(ApiDataSource.SQL_DICT))
@@ -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