diff --git a/.markdownlint.yaml b/.markdownlint.yaml
new file mode 100644
index 00000000..d2c1095d
--- /dev/null
+++ b/.markdownlint.yaml
@@ -0,0 +1,4 @@
+MD013: false
+MD024: # 重复标题
+ siblings_only: true
+MD033: false # 允许 html
\ No newline at end of file
diff --git a/README.md b/README.md
index ad8f1491..59db485c 100644
--- a/README.md
+++ b/README.md
@@ -1,21 +1,43 @@
+
-

+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-[](https://github.com/HibiKier/zhenxun_bot/blob/main/LICENSE)
-[](https://jq.qq.com/?_wv=1027&k=u8PgBkMZ)
+[](https://qm.qq.com/q/mRNtLSl6uc)
[](https://qm.qq.com/q/YYYt5rkMYc)
@@ -36,7 +58,7 @@
“真寻是[椛椛](https://github.com/FloatTech/ZeroBot-Plugin)的好朋友!”
-:tada:喜欢真寻,于是真寻就来了!:tada:
+🎉喜欢真寻,于是真寻就来了!🎉
本项目符合 [OneBot](https://github.com/howmanybots/onebot) 标准,可基于以下项目与机器人框架/平台进行交互
@@ -50,28 +72,27 @@
-
+
-## 真寻觉得你需要帮助
+## 🤝 帮助页面
-
+
+点击展开查看图片
+
+
+
+
-

-

-

-
-
-
-## 这是一份扩展
+## 📦 这是一份扩展
### 1. 体验一下?
这是一个免费的,版本为 dev 的 zhenxun,你可以通过 [napcat](https://github.com/NapNeko/NapCatQQ) 或 [拉格朗日](https://github.com/LagrangeDev/Lagrange.Core) 以及 [matcha](https://github.com/A-kirami/matcha) 等直接连接用于体验与测试
(球球了测试君!)
-```
+```text
Url: ws://test.zhenxun.org:8080/onebot/v11/ws
AccessToken: PUBLIC_ZHENXUN_TEST
@@ -89,39 +110,23 @@ AccessToken: PUBLIC_ZHENXUN_TEST
| [插件库](https://github.com/zhenxun-org/zhenxun_bot_plugins) | 插件 | [zhenxun-org](https://github.com/zhenxun-org) | 原 plugins 文件夹插件 |
| [插件索引库](https://github.com/zhenxun-org/zhenxun_bot_plugins_index) | 插件 | [zhenxun-org](https://github.com/zhenxun-org) | 扩展插件索引库 |
| [一键安装](https://github.com/soloxiaoye2022/zhenxun_bot-deploy) | 安装 | [soloxiaoye2022](https://github.com/soloxiaoye2022) | 第三方 |
-| [WebUi](https://github.com/HibiKier/zhenxun_bot_webui) | 管理 | [hibikier](https://github.com/HibiKier) | 基于真寻 WebApi 的 webui 实现 |
+| [WebUi](https://github.com/HibiKier/zhenxun_bot_webui) | 管理 | [hibikier](https://github.com/HibiKier) | 基于真寻 WebApi 的 webui 实现 [预览](#-webui界面展示) |
| [安卓 app(WebUi)](https://github.com/YuS1aN/zhenxun_bot_android_ui) | 安装 | [YuS1aN](https://github.com/YuS1aN) | 第三方 |
-
- WebUI 后台示例图
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-## ~~来点优点?~~ 可爱难道还不够吗
+## 🥰 ~~来点优点?~~ 可爱难道还不够吗
- 实现了许多功能,且提供了大量功能管理命令,进行了多平台适配,兼容 nb2 商店插件
- 拥有完善可用的 webui
- 通过 Config 配置项将所有插件配置统计保存至 config.yaml,利于统一用户修改
- 方便增删插件,原生 nonebot2 matcher,不需要额外修改,仅仅通过简单的配置属性就可以生成`帮助图片`和`帮助信息`
- 提供了 cd,阻塞,每日次数等限制,仅仅通过简单的属性就可以生成一个限制,例如:`PluginCdBlock` 等
-- **..... 更多详细请通过[[传送门](https://hibikier.github.io/zhenxun_bot/)]查看文档!**
+- **更多详细请通过 [传送门](https://hibikier.github.io/zhenxun_bot/) 查看文档!**
-## 简单部署
+## 🛠️ 简单部署
-```
+```bash
# 获取代码
git clone https://github.com/HibiKier/zhenxun_bot.git
@@ -134,636 +139,154 @@ poetry install # 安装依赖
# 开始运行
poetry shell # 进入虚拟环境
-python bot.py
-
-# 首次后会在data目录下生成config.yaml文件
-# config.yaml用户配置插件
+python bot.py # 运行机器人
```
-## 简单配置
+## 📝 简单配置
-```
-1.在.env.dev文件中
+> [!TIP]
+> config.yaml 需要启动一次 Bot 后生成
- SUPERUSERS = [""] # 填写你的QQ
+1.在 .env.dev 文件中填写你的机器人配置项
- PLATFORM_SUPERUSERS = '
- {
- "qq": [""], # 在此处填写你的qq
- "dodo": [],
- "kaiheila": [],
- "discord": []
- }
- '
- # 此处填写你的数据库地址
- # 示例: "postgres://user:password@127.0.0.1:5432/database"
- # 示例: "mysql://user:password@127.0.0.1:5432/database"
- # 示例: "sqlite:data/db/zhenxun.db" 在data目录下建立db文件夹
- DB_URL = "" # 数据库地址
+2.在 configs/config.yaml 文件中修改你需要修改的插件配置项
+
+数据库地址(DB_URL)配置说明
-2.在configs/config.yaml文件中 # 该文件需要启动一次后生成
- * 修改插件配置项
+DB_URL 是基于 Tortoise ORM 的数据库连接字符串,用于指定项目所使用的数据库。以下是 DB_URL 的组成部分以及示例:
-```
+格式为: ```<数据库类型>://<用户名>:<密码>@<主机>:<端口>/<数据库名>?<参数>```
-## 功能列表
+- 数据库类型:表示数据库类型,例如 postgres、mysql、sqlite 等。
+- 用户名:数据库的用户名,例如 root。
+- 密码:数据库的密码,例如 123456。
+- 主机:数据库的主机地址,例如 127.0.0.1(本地)或远程服务器 IP。
+- 端口:数据库的端口号,例如:PostgreSQL:5432, MySQL:3306
+- 数据库名:指定要使用的数据库名称,例如 zhenxun。
+- 参数(可选):用于传递额外的配置,例如字符集设置。
+
+
+
+## 📋 功能列表
+
+> [!NOTE]
+> 真寻原 `plugins` 插件文件夹已迁移至 [插件仓库](https://github.com/zhenxun-org/zhenxun_bot_plugins) ,现在本体仅保留核心功能
内置功能
-**真寻原 `plugins` 插件文件夹已迁移至其他仓库,当前内置仅保留必要的功能**
+### 🔧 基础功能
-### 基础功能
+- 昵称系统(群与群与私聊分开)
+- 签到/我的签到/好感度排行/好感度总排行(影响色图概率和开箱次数,支持配置)
+- 商店/我的金币/购买道具/使用道具/金币排行(完整的商店添加/购买/使用流程)
+- 查看当前群欢迎消息
+- 个人信息查看(群组内权限,聊天频率等)
+- 消息撤回
+- 功能统计可视化
+- 关于
+- 三种样式的帮助菜单
-- [x] 昵称系统(群与群与私聊分开)
-- [x] 签到/我的签到/好感度排行/好感度总排行(影响色图概率和开箱次数,支持配置)
-- [x] 商店/我的金币/购买道具/使用道具/金币排行(完整的商店添加/购买/使用流程)
-- [x] 查看当前群欢迎消息
-- [x] 个人信息查看(群组内权限,聊天频率等)
-- [x] 消息撤回
-- [x] 功能统计可视化
-- [x] 关于
-- [x] 三种样式的帮助菜单
+### 🛠️ 管理员功能
-### 管理员功能
+- 管理员帮助
+- 更新群组成员信息
+- 95%的群功能开关
+- 查看群内被动技能状态
+- 自定义群欢迎消息(是真寻的不是管家的!)
+- ban/unban(支持设置 ban 时长)= 群组及用户的黑名单
+- 休息吧/醒来(群组内真寻状态)
-- [x] 管理员帮助
-- [x] 更新群组成员信息
-- [x] 95%的群功能开关
-- [x] 查看群内被动技能状态
-- [x] 自定义群欢迎消息(是真寻的不是管家的!)
-- [x] ban/unban(支持设置 ban 时长)= 群组及用户的黑名单
-- [x] 休息吧/醒来(群组内真寻状态)
+### 🧑💼 超级用户功能
-### 超级用户功能
+- 超级用户帮助
+- 添加/删除权限(是真寻的管理员权限,不是群管理员)
+- 群组管理,退群指令等
+- 广播
+- 自检(检查系统状态)
+- 所有群组/所有好友
+- 退出指定群
+- 更新好友信息/更新群信息
+- 修改群权限
+- 检查更新
+- 重启
+- 添加/删除/查看群白名单
+- 功能开关(更多设置)
+- 功能状态
+- 执行 SQL
+- 重载配置
+- 清理临时数据
+- 增删群认证
+- 同意/拒绝好友/群聊请求
+- 添加/移除/更新插件/插件商店(plugins 库以及扩展库)
+- WebUI API(对真寻前端的支持)
-- [x] 超级用户帮助
-- [x] 添加/删除权限(是真寻的管理员权限,不是群管理员)
-- [x] 群组管理,退群指令等
-- [x] 广播
-- [x] 自检(检查系统状态)
-- [x] 所有群组/所有好友
-- [x] 退出指定群
-- [x] 更新好友信息/更新群信息
-- [x] 修改群权限
-- [x] 检查更新
-- [x] 重启
-- [x] 添加/删除/查看群白名单
-- [x] 功能开关(更多设置)
-- [x] 功能状态
-- [x] 执行 SQL
-- [x] 重载配置
-- [x] 清理临时数据
-- [x] 增删群认证
-- [x] 同意/拒绝好友/群聊请求
-- [x] 添加/移除/更新插件/插件商店(plugins 库以及扩展库)
-- [x] WebUI API(对真寻前端的支持)
+#### 🛡️ 超级用户的被动技能
-#### 超级用户的被动技能
+- 邀请入群提醒(别人邀请真寻入群,可配置自动同意)
-- [x] 邀请入群提醒(别人邀请真寻入群,可配置自动同意)
+- 添加好友提醒(别人添加真寻好友,可配置自动同意)
-- [x] 添加好友提醒(别人添加真寻好友,可配置自动同意)
+### 🤖 被动技能
-### 被动技能
+- 群早晚安
-- [x] 群早晚安
+### 👻 看不见的技能
-### 看不见的技能
-
-- [x] 功能调用统计
-- [x] 聊天记录统计
-- [x] 检测恶意触发命令(将被最高权限 ban 掉 30 分钟,只有最高权限(9 级)可以进行 unban)
-- [x] 自动同意好友/群组请求,加群请求将会提醒管理员,退群提示,加群欢迎等等
-- [x] 群聊时间检测(当群聊最后一人发言时间大于当前 48 小时后将关闭该群所有通知(即被动技能))
-- [x] 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限
-- [x] 群权限系统
-- [x] 定时更新权限
-- [x] 自动配置重载
-- [x] 强制入群保护
-- [x] 自定备份(可配置)
-- [x] 笨蛋检测(当使用功能名称当指令时真寻会跳出来狠狠嘲笑并帮助)
-
-### 更多插件
-
-- [更多插件](https://github.com/zhenxun-org/zhenxun_bot_plugins)
-
-- [第三方插件索引库](https://github.com/zhenxun-org/zhenxun_bot_plugins_index)
+- 功能调用统计
+- 聊天记录统计
+- 检测恶意触发命令(将被最高权限 ban 掉 30 分钟,只有最高权限(9 级)可以进行 unban)
+- 自动同意好友/群组请求,加群请求将会提醒管理员,退群提示,加群欢迎等等
+- 群聊时间检测(当群聊最后一人发言时间大于当前 48 小时后将关闭该群所有通知(即被动技能))
+- 群管理员监控,自动为新晋管理员增加权限,为失去群管理员的用户删除权限
+- 群权限系统
+- 定时更新权限
+- 自动配置重载
+- 强制入群保护
+- 自定备份(可配置)
+- 笨蛋检测(当使用功能名称当指令时真寻会跳出来狠狠嘲笑并帮助)
-## [爱发电](https://afdian.com/a/HibiKier)
+## 💖 赞助
-爱发电 以及 感谢投喂
-
+爱发电
+
+
+
+
-### 感谢名单
+### 赞助名单
(可以告诉我你的 **github** 地址,我偷偷换掉 0v|)
-[shenqi](https://afdian.net/u/fa923a8cfe3d11eba61752540025c377)
-[A_Kyuu](https://afdian.net/u/b83954fc2c1211eba9eb52540025c377)
-[疯狂混沌](https://afdian.net/u/789a2f9200cd11edb38352540025c377)
-[投冥](https://afdian.net/a/144514mm)
-[茶喵](https://afdian.net/u/fd22382eac4d11ecbfc652540025c377)
-[AemokpaTNR](https://afdian.net/u/1169bb8c8a9611edb0c152540025c377)
-[爱发电用户\_wrxn](https://afdian.net/u/4aa03d20db4311ecb1e752540025c377)
-[qqw](https://afdian.net/u/b71db4e2cc3e11ebb76652540025c377)
-[溫一壺月光下酒](https://afdian.net/u/ad667a5c650c11ed89bf52540025c377)
-[伝木](https://afdian.net/u/246b80683f9511edba7552540025c377)
-[阿奎](https://afdian.net/u/da41f72845d511ed930d52540025c377)
-[醉梦尘逸](https://afdian.net/u/bc11d2683cd011ed99b552540025c377)
-[Abc](https://afdian.net/u/870dc10a3cd311ed828852540025c377)
-[本喵无敌哒](https://afdian.net/u/dffaa9005bc911ebb69b52540025c377)
-[椎名冬羽](https://afdian.net/u/ca1ebd64395e11ed81b452540025c377)
-[kaito](https://afdian.net/u/a055e20a498811eab1f052540025c377)
-[笑柒 XIAO_Q7](https://afdian.net/u/4696db5c529111ec84ea52540025c377)
-[请问一份爱多少钱](https://afdian.net/u/f57ef6602dbd11ed977f52540025c377)
-[咸鱼鱼鱼鱼](https://afdian.net/u/8e39b9a400e011ed9f4a52540025c377)
-[Kafka](https://afdian.net/u/41d66798ef6911ecbc5952540025c377)
-[墨然](https://afdian.net/u/8aa5874a644d11eb8a6752540025c377)
-[爱发电用户\_T9e4](https://afdian.net/u/2ad1bb82f3a711eca22852540025c377)
-[笑柒 XIAO_Q7](https://afdian.net/u/4696db5c529111ec84ea52540025c377)
-[noahzark](https://afdian.net/a/noahzark)
-[腊条](https://afdian.net/u/f739c4d69eca11eba94b52540025c377)
-[ze roller](https://afdian.net/u/0e599e96257211ed805152540025c377)
-[爱发电用户\_4jrf](https://afdian.net/u/6b2cdcc817c611ed949152540025c377)
-[爱发电用户\_TBsd](https://afdian.net/u/db638b60217911ed9efd52540025c377)
-[烟寒若雨](https://afdian.net/u/067bd2161eec11eda62b52540025c377)
-[ln](https://afdian.net/u/b51914ba1c6611ed8a4e52540025c377)
-[爱发电用户\_b9S4](https://afdian.net/u/3d8f30581a2911edba6d52540025c377)
-[爱发电用户\_c58s](https://afdian.net/u/a6ad8dda195e11ed9a4152540025c377)
-[爱发电用户\_eNr9](https://afdian.net/u/05fdb41c0c9a11ed814952540025c377)
-[MangataAkihi](https://github.com/Sakuracio)
-[炀](https://afdian.net/u/69b76e9ec77b11ec874f52540025c377)
-[爱发电用户\_Bc6j](https://afdian.net/u/8546be24f44111eca64052540025c377)
-[大魔王](https://github.com/xipesoy)
-[CopilotLaLaLa](https://github.com/CopilotLaLaLa)
-[嘿小欧](https://afdian.net/u/daa4bec4f24911ec82e552540025c377)
-[回忆的秋千](https://afdian.net/u/e315d9c6f14f11ecbeef52540025c377)
-[十年くん](https://github.com/shinianj)
-[哇](https://afdian.net/u/9b266244f23911eca19052540025c377)
-[yajiwa](https://github.com/yajiwa)
-[爆金币](https://afdian.net/u/0d78879ef23711ecb22452540025c377)
-...
+[shenqi](https://afdian.net/u/fa923a8cfe3d11eba61752540025c377) [A_Kyuu](https://afdian.net/u/b83954fc2c1211eba9eb52540025c377) [疯狂混沌](https://afdian.net/u/789a2f9200cd11edb38352540025c377) [投冥](https://afdian.net/a/144514mm) [茶喵](https://afdian.net/u/fd22382eac4d11ecbfc652540025c377) [AemokpaTNR](https://afdian.net/u/1169bb8c8a9611edb0c152540025c377) [爱发电用户\_wrxn](https://afdian.net/u/4aa03d20db4311ecb1e752540025c377) [qqw](https://afdian.net/u/b71db4e2cc3e11ebb76652540025c377) [溫一壺月光下酒](https://afdian.net/u/ad667a5c650c11ed89bf52540025c377) [伝木](https://afdian.net/u/246b80683f9511edba7552540025c377) [阿奎](https://afdian.net/u/da41f72845d511ed930d52540025c377) [醉梦尘逸](https://afdian.net/u/bc11d2683cd011ed99b552540025c377) [Abc](https://afdian.net/u/870dc10a3cd311ed828852540025c377) [本喵无敌哒](https://afdian.net/u/dffaa9005bc911ebb69b52540025c377) [椎名冬羽](https://afdian.net/u/ca1ebd64395e11ed81b452540025c377) [kaito](https://afdian.net/u/a055e20a498811eab1f052540025c377) [笑柒 XIAO_Q7](https://afdian.net/u/4696db5c529111ec84ea52540025c377) [请问一份爱多少钱](https://afdian.net/u/f57ef6602dbd11ed977f52540025c377) [咸鱼鱼鱼鱼](https://afdian.net/u/8e39b9a400e011ed9f4a52540025c377) [Kafka](https://afdian.net/u/41d66798ef6911ecbc5952540025c377) [墨然](https://afdian.net/u/8aa5874a644d11eb8a6752540025c377) [爱发电用户\_T9e4](https://afdian.net/u/2ad1bb82f3a711eca22852540025c377) [笑柒 XIAO_Q7](https://afdian.net/u/4696db5c529111ec84ea52540025c377) [noahzark](https://afdian.net/a/noahzark) [腊条](https://afdian.net/u/f739c4d69eca11eba94b52540025c377) [ze roller](https://afdian.net/u/0e599e96257211ed805152540025c377) [爱发电用户\_4jrf](https://afdian.net/u/6b2cdcc817c611ed949152540025c377) [爱发电用户\_TBsd](https://afdian.net/u/db638b60217911ed9efd52540025c377) [烟寒若雨](https://afdian.net/u/067bd2161eec11eda62b52540025c377) [ln](https://afdian.net/u/b51914ba1c6611ed8a4e52540025c377) [爱发电用户\_b9S4](https://afdian.net/u/3d8f30581a2911edba6d52540025c377) [爱发电用户\_c58s](https://afdian.net/u/a6ad8dda195e11ed9a4152540025c377) [爱发电用户\_eNr9](https://afdian.net/u/05fdb41c0c9a11ed814952540025c377) [MangataAkihi](https://github.com/Sakuracio) [炀](https://afdian.net/u/69b76e9ec77b11ec874f52540025c377) [爱发电用户\_Bc6j](https://afdian.net/u/8546be24f44111eca64052540025c377) [大魔王](https://github.com/xipesoy) [CopilotLaLaLa](https://github.com/CopilotLaLaLa) [嘿小欧](https://afdian.net/u/daa4bec4f24911ec82e552540025c377) [回忆的秋千](https://afdian.net/u/e315d9c6f14f11ecbeef52540025c377) [十年くん](https://github.com/shinianj) [哇](https://afdian.net/u/9b266244f23911eca19052540025c377) [yajiwa](https://github.com/yajiwa) [爆金币](https://afdian.net/u/0d78879ef23711ecb22452540025c377)...
-
+## 📜 贡献指南
-
+> [!TIP]
+> 发起 [issue](https://github.com/HibiKier/zhenxun_bot/issues/new/choose) 前,我们希望你能够阅读过或者了解 [提问的智慧](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md)
+>
+> - 善用[搜索引擎](https://www.google.com/)
+> - 查阅 issue 中是否有类似问题,如果没有请按照模板发起 issue
-
-
-
-
-**..... 更多更新信息请查看文档**
-
-## Todo
-
-- [x] web 管理
-
-## **特别感谢**
+## 🌟 特别感谢
首席设计师:[酥酥/coldly-ss](https://github.com/coldly-ss)
-## 感谢
+## 🙏 感谢
[botuniverse / onebot](https://github.com/botuniverse/onebot) :超棒的机器人协议
[Mrs4s / go-cqhttp](https://github.com/Mrs4s/go-cqhttp) :cqhttp 的 golang 实现,轻量、原生跨平台.
@@ -778,3 +301,58 @@ python bot.py
[Kyomotoi / AnimeThesaurus](https://github.com/Kyomotoi/AnimeThesaurus) :一个~~特二刺螈~~(文爱)的适用于任何 bot 的词库
[Ailitonia / omega-miya](https://github.com/Ailitonia/omega-miya) :基于 nonebot2 的 qq 机器人
[KimigaiiWuyi / GenshinUID](https://github.com/KimigaiiWuyi/GenshinUID) :一个基于 HoshinoBot/NoneBot2 的原神 UID 查询插件
+
+## 📊 统计与活跃贡献者
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## 👨💻 开发者
+
+感谢以下开发者对 绪山真寻 Bot 作出的贡献:
+
+
+
+
+
+## 📸 WebUI界面展示
+
+
+
+

+
+
+

+
+
+
+

+
+
+

+
+
+
+

+
+
+

+
+
+
+

+
+
+

+
+
diff --git a/resources/template/check/main.css b/resources/template/check/main.css
index f6790712..645efa15 100644
--- a/resources/template/check/main.css
+++ b/resources/template/check/main.css
@@ -44,7 +44,7 @@ body {
}
.main {
- height: 448px;
+ height: 444px;
width: 335px;
padding: 0 30px;
position: relative;
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/hooks/_auth_checker.py b/zhenxun/builtin_plugins/hooks/_auth_checker.py
index 7e2e179c..2276a8fa 100644
--- a/zhenxun/builtin_plugins/hooks/_auth_checker.py
+++ b/zhenxun/builtin_plugins/hooks/_auth_checker.py
@@ -387,7 +387,7 @@ class AuthChecker:
session=session,
)
raise IgnoredException("该群未开启此功能...")
- if not plugin.status and plugin.block_type == BlockType.GROUP:
+ if plugin.block_type == BlockType.GROUP:
"""全局群组禁用"""
try:
if self.is_send_limit_message(plugin, sid) and not is_poke:
@@ -410,7 +410,7 @@ class AuthChecker:
raise IgnoredException("该插件在群组中已被禁用...")
else:
sid = user_id
- if not plugin.status and plugin.block_type == BlockType.PRIVATE:
+ if plugin.block_type == BlockType.PRIVATE:
"""全局私聊禁用"""
try:
if self.is_send_limit_message(plugin, sid) and not is_poke:
diff --git a/zhenxun/builtin_plugins/init/init_plugin.py b/zhenxun/builtin_plugins/init/init_plugin.py
index ffcc8b4d..366df312 100644
--- a/zhenxun/builtin_plugins/init/init_plugin.py
+++ b/zhenxun/builtin_plugins/init/init_plugin.py
@@ -120,7 +120,7 @@ async def _():
if module_list := await PluginInfo.all().values("id", "module_path"):
module2id = {m["module_path"]: m["id"] for m in module_list}
for plugin in get_loaded_plugins():
- load_plugin.append(plugin.name)
+ load_plugin.append(plugin.module_name)
await _handle_setting(plugin, plugin_list, limit_list, task_list)
create_list = []
update_list = []
@@ -198,8 +198,8 @@ async def _():
10,
)
await data_migration()
- await PluginInfo.filter(module__in=load_plugin).update(load_status=True)
- await PluginInfo.filter(module__not_in=load_plugin).update(load_status=False)
+ await PluginInfo.filter(module_path__in=load_plugin).update(load_status=True)
+ await PluginInfo.filter(module_path__not_in=load_plugin).update(load_status=False)
manager.init()
if limit_list:
for limit in limit_list:
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/scheduler/chat_check.py b/zhenxun/builtin_plugins/scheduler/chat_check.py
index 4c30ffe2..d7559665 100644
--- a/zhenxun/builtin_plugins/scheduler/chat_check.py
+++ b/zhenxun/builtin_plugins/scheduler/chat_check.py
@@ -37,8 +37,7 @@ async def _():
update_list = []
if modules := await TaskInfo.annotate().values_list("module", flat=True):
for bot in nonebot.get_bots().values():
- group_list, _ = await PlatformUtils.get_group_list(bot)
- group_list = [g for g in group_list if g.channel_id is None]
+ group_list, _ = await PlatformUtils.get_group_list(bot, True)
for group in group_list:
try:
last_message = (
diff --git a/zhenxun/builtin_plugins/shop/__init__.py b/zhenxun/builtin_plugins/shop/__init__.py
index 104ae88e..bc663e28 100644
--- a/zhenxun/builtin_plugins/shop/__init__.py
+++ b/zhenxun/builtin_plugins/shop/__init__.py
@@ -126,7 +126,9 @@ async def _(session: Uninfo, arparma: Arparma):
async def _(session: Uninfo, arparma: Arparma, nickname: str = UserName()):
logger.info("查看道具", arparma.header_result, session=session)
if image := await ShopManage.my_props(
- session.user.id, nickname, PlatformUtils.get_platform(session)
+ session.user.id,
+ nickname,
+ PlatformUtils.get_platform(session),
):
await MessageUtils.build_message(image.pic2bytes()).finish(reply_to=True)
return await MessageUtils.build_message("你的道具为空捏...").send(reply_to=True)
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..afa325f9 100644
--- a/zhenxun/builtin_plugins/web_ui/__init__.py
+++ b/zhenxun/builtin_plugins/web_ui/__init__.py
@@ -13,6 +13,7 @@ from zhenxun.utils.enum import PluginType
from .api.logs import router as ws_log_routes
from .api.logs.log_manager import LOG_STORAGE
+from .api.menu import router as menu_router
from .api.tabs.dashboard import router as dashboard_router
from .api.tabs.database import router as database_router
from .api.tabs.main import router as main_router
@@ -80,6 +81,7 @@ BaseApiRouter.include_router(manage_router)
BaseApiRouter.include_router(database_router)
BaseApiRouter.include_router(plugin_router)
BaseApiRouter.include_router(system_router)
+BaseApiRouter.include_router(menu_router)
WsApiRouter = APIRouter(prefix="/zhenxun/socket")
@@ -112,6 +114,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/__init__.py b/zhenxun/builtin_plugins/web_ui/api/__init__.py
index de9b3798..3608647c 100644
--- a/zhenxun/builtin_plugins/web_ui/api/__init__.py
+++ b/zhenxun/builtin_plugins/web_ui/api/__init__.py
@@ -1 +1,2 @@
-from .tabs import * # noqa: F403
+from .menu import * # noqa: F403f
+from .tabs import * # noqa: F403f
diff --git a/zhenxun/builtin_plugins/web_ui/api/menu/__init__.py b/zhenxun/builtin_plugins/web_ui/api/menu/__init__.py
new file mode 100644
index 00000000..aca8baef
--- /dev/null
+++ b/zhenxun/builtin_plugins/web_ui/api/menu/__init__.py
@@ -0,0 +1,26 @@
+from fastapi import APIRouter
+from fastapi.responses import JSONResponse
+
+from zhenxun.services.log import logger
+
+from ...base_model import Result
+from ...utils import authentication
+from .data_source import menu_manage
+from .model import MenuData
+
+router = APIRouter(prefix="/menu")
+
+
+@router.get(
+ "/get_menus",
+ dependencies=[authentication()],
+ response_model=Result[list[MenuData]],
+ response_class=JSONResponse,
+ deprecated="获取菜单列表", # type: ignore
+)
+async def _() -> Result[list[MenuData]]:
+ try:
+ return Result.ok(menu_manage.get_menus(), "拿到菜单了哦!")
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_menus 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
diff --git a/zhenxun/builtin_plugins/web_ui/api/menu/data_source.py b/zhenxun/builtin_plugins/web_ui/api/menu/data_source.py
new file mode 100644
index 00000000..1f530a3c
--- /dev/null
+++ b/zhenxun/builtin_plugins/web_ui/api/menu/data_source.py
@@ -0,0 +1,64 @@
+import ujson as json
+
+from zhenxun.configs.path_config import DATA_PATH
+from zhenxun.services.log import logger
+
+from .model import MenuData, MenuItem
+
+
+class MenuManage:
+ def __init__(self) -> None:
+ self.file = DATA_PATH / "web_ui" / "menu.json"
+ self.menu = []
+ if self.file.exists():
+ try:
+ self.menu = json.load(self.file.open(encoding="utf8"))
+ except Exception as e:
+ logger.warning("菜单文件损坏,已重新生成...", "WebUi", e=e)
+ if not self.menu:
+ self.menu = [
+ MenuItem(
+ name="仪表盘",
+ module="dashboard",
+ router="/dashboard",
+ icon="dashboard",
+ default=True,
+ ),
+ MenuItem(
+ name="真寻控制台",
+ module="command",
+ router="/command",
+ icon="command",
+ ),
+ MenuItem(
+ name="插件列表", module="plugin", router="/plugin", icon="plugin"
+ ),
+ MenuItem(
+ name="插件商店", module="store", router="/store", icon="store"
+ ),
+ MenuItem(
+ name="好友/群组", module="manage", router="/manage", icon="user"
+ ),
+ MenuItem(
+ name="数据库管理",
+ module="database",
+ router="/database",
+ icon="database",
+ ),
+ MenuItem(
+ name="系统信息", module="system", router="/system", icon="system"
+ ),
+ ]
+ self.save()
+
+ def get_menus(self):
+ return MenuData(menus=self.menu)
+
+ def save(self):
+ self.file.parent.mkdir(parents=True, exist_ok=True)
+ temp = [menu.dict() for menu in self.menu]
+ with self.file.open("w", encoding="utf8") as f:
+ json.dump(temp, f, ensure_ascii=False, indent=4)
+
+
+menu_manage = MenuManage()
diff --git a/zhenxun/builtin_plugins/web_ui/api/menu/model.py b/zhenxun/builtin_plugins/web_ui/api/menu/model.py
new file mode 100644
index 00000000..abd73a69
--- /dev/null
+++ b/zhenxun/builtin_plugins/web_ui/api/menu/model.py
@@ -0,0 +1,21 @@
+from pydantic import BaseModel
+
+
+class MenuItem(BaseModel):
+ module: str
+ """模块名称"""
+ name: str
+ """菜单名称"""
+ router: str
+ """路由"""
+ icon: str
+ """图标"""
+ default: bool = False
+ """默认选中"""
+
+
+class MenuData(BaseModel):
+ bot_type: str = "zhenxun"
+ """bot类型"""
+ menus: list[MenuItem]
+ """菜单列表"""
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 02754a22..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信息
@@ -47,8 +51,7 @@ class BotManage:
bot_info = BotInfo(
self_id=bot.self_id, nickname=nickname, ava_url=ava_url, platform=platform
)
- group_list, _ = await PlatformUtils.get_group_list(bot)
- group_list = [g for g in group_list if g.channel_id is None]
+ group_list, _ = await PlatformUtils.get_group_list(bot, True)
friend_list, _ = await PlatformUtils.get_friend_list(bot)
bot_info.group_count = len(group_list)
bot_info.friend_count = len(friend_list)
@@ -77,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..7b495c1c 100644
--- a/zhenxun/builtin_plugins/web_ui/api/tabs/database/__init__.py
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/database/__init__.py
@@ -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))
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 91341cc5..36059101 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,28 +7,26 @@ 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.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.bot_console import BotConsole
from zhenxun.services.log import logger
+from zhenxun.utils.common_utils import CommonUtils
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,
+ BotBlockModule,
+ BotManageUpdateParam,
+ BotStatusParam,
HotPlugin,
NonebotData,
QueryCount,
- TemplateBaseInfo,
)
driver = nonebot.get_driver()
@@ -56,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 = await bot.get_login_info()
- bot_list.append(
- TemplateBaseInfo(
- bot=bot, # type: ignore
- self_id=bot.self_id,
- nickname=login_info["nickname"],
- 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 select_bot.bot.get_group_list())
- # 好友数量
- select_bot.friend_count = len(await select_bot.bot.get_friend_list())
- for bot in bot_list:
- bot.bot = None # type: ignore
- # 插件加载数量
- select_bot.plugin_count = await PluginInfo.all().count()
- fail_count = await PluginInfo.filter(load_status=False).count()
- select_bot.fail_plugin_count = fail_count
- select_bot.success_plugin_count = (
- select_bot.plugin_count - select_bot.fail_plugin_count
- )
- # 连接时间
- 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(
@@ -124,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(
@@ -160,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(
@@ -196,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, KeyError):
+ 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(
@@ -219,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)))
@@ -241,6 +145,7 @@ async def _() -> Result[Config]:
description="获取nb运行时间",
)
async def _() -> Result[int]:
+ global run_time
return Result.ok(int(run_time))
@@ -254,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(
@@ -308,37 +178,66 @@ 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(
+ "/change_bot_status",
+ dependencies=[authentication()],
+ response_model=Result,
+ response_class=JSONResponse,
+ description="修改bot全局开关",
+)
+async def _(param: BotStatusParam):
+ try:
+ await BotConsole.set_bot_status(param.status, param.bot_id)
+ return Result.ok(info="修改bot全局开关成功!")
+ except (ValueError, KeyError):
+ return Result.fail("Bot未初始化...")
+
+
+@router.get(
+ "/get_bot_block_module",
+ dependencies=[authentication()],
+ response_model=Result[BotBlockModule],
+ response_class=JSONResponse,
+ description="获取bot层面的禁用模块",
+)
+async def _(bot_id: str) -> Result[BotBlockModule]:
+ try:
+ return Result.ok(
+ await ApiDataSource.get_bot_block_module(bot_id), "拿到信息啦!"
+ )
+ except Exception as e:
+ logger.error(f"{router.prefix}/get_bot_block_module 调用错误", "WebUi", e=e)
+ return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
+
+
+@router.post(
+ "/update_bot_manage",
+ dependencies=[authentication()],
+ response_model=Result,
+ response_class=JSONResponse,
+ description="修改bot全局开关",
+)
+async def _(param: BotManageUpdateParam):
+ 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/main/model.py b/zhenxun/builtin_plugins/web_ui/api/tabs/main/model.py
index 95a65515..a38be06f 100644
--- a/zhenxun/builtin_plugins/web_ui/api/tabs/main/model.py
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/main/model.py
@@ -1,8 +1,45 @@
+from typing import Any
+
from nonebot.adapters import Bot
from nonebot.config import Config
from pydantic import BaseModel
+class BotManageUpdateParam(BaseModel):
+ """bot更新参数"""
+
+ bot_id: str
+ """bot id"""
+ block_plugins: list[str]
+ """禁用插件"""
+ block_tasks: list[str]
+ """禁用被动"""
+
+
+class BotStatusParam(BaseModel):
+ """bot状态参数"""
+
+ bot_id: str
+ """bot id"""
+ status: bool
+ """状态"""
+
+
+class BotBlockModule(BaseModel):
+ """bot禁用模块参数"""
+
+ bot_id: str
+ """bot id"""
+ block_plugins: list[str]
+ """禁用插件"""
+ block_tasks: list[str]
+ """禁用被动"""
+ all_plugins: list[dict[str, Any]]
+ """所有插件"""
+ all_tasks: list[dict[str, Any]]
+ """所有被动"""
+
+
class SystemStatus(BaseModel):
"""
系统状态
@@ -36,13 +73,8 @@ class BaseInfo(BaseModel):
"""连接日期"""
connect_count: int = 0
"""连接次数"""
-
- plugin_count: int = 0
- """加载插件数量"""
- success_plugin_count: int = 0
- """加载成功插件数量"""
- fail_plugin_count: int = 0
- """加载失败插件数量"""
+ status: bool = False
+ """全局状态"""
is_select: bool = False
"""当前选择"""
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 12d3cbdb..87288465 100644
--- a/zhenxun/builtin_plugins/web_ui/api/tabs/manage/__init__.py
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/manage/__init__.py
@@ -2,16 +2,9 @@ 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.enum import RequestHandleType, RequestType
from zhenxun.utils.exception import NotFoundError
@@ -20,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,
)
@@ -52,19 +42,21 @@ 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, KeyError):
+ return Result.warning_("指定Bot未连接...")
except Exception as e:
- logger.error("调用API错误", "/get_group_list", e=e)
+ logger.error(f"{router.prefix}/get_group_list 调用错误", "WebUi", e=e)
return Result.fail(f"{type(e)}: {e}")
return Result.ok(group_list_result, "拿到了新鲜出炉的数据!")
@@ -78,25 +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:
- group.close_plugins = [f"<{module}" for module in group.close_plugins]
- db_group.block_plugin = ",".join(group.close_plugins) + ","
- if group.task:
- if block_task := [t for t in task_list if t not in group.task]:
- block_task = [f"<{module}" for module in block_task]
- db_group.block_task = ",".join(block_task) + "," # 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(
@@ -110,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, KeyError):
+ 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(
@@ -138,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(
@@ -160,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(
@@ -220,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, KeyError):
+ 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}")
@@ -247,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="成功处理了请求!")
@@ -259,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, KeyError):
+ 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}")
@@ -297,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 bots[bot_id].get_group_list()
- if param.group_id not in [str(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, KeyError):
+ 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}")
@@ -322,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, KeyError):
+ 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}")
@@ -346,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, KeyError):
+ 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(
@@ -392,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(
@@ -483,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, KeyError):
+ 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 fb77ac2d..3e45ad03 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
@@ -1,18 +1,14 @@
-import re
-
-import cattrs
from fastapi import APIRouter, Query
from fastapi.responses import JSONResponse
-from zhenxun.configs.config import Config
from zhenxun.models.plugin_info import PluginInfo as DbPluginInfo
from zhenxun.services.log import logger
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,
PluginDetail,
PluginInfo,
@@ -34,31 +30,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)
- 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 +46,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,33 +75,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)
+ await ApiDataSource.update_plugin(param)
+ return Result.ok(info="已经帮你写好啦!")
+ except (ValueError, KeyError):
+ 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(
@@ -130,17 +94,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(
@@ -151,12 +119,20 @@ async def _(param: PluginSwitch) -> Result:
description="获取插件类型",
)
async def _() -> Result[list[str]]:
- menu_type_list = []
- result = await DbPluginInfo.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(
@@ -167,46 +143,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, KeyError):
+ 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..ee0992d6
--- /dev/null
+++ b/zhenxun/builtin_plugins/web_ui/api/tabs/plugin_manage/data_source.py
@@ -0,0 +1,152 @@
+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 as DbPluginInfo
+from zhenxun.utils.enum import BlockType, PluginType
+
+from .model import PluginConfig, PluginDetail, PluginInfo, 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/builtin_plugins/web_ui/base_model.py b/zhenxun/builtin_plugins/web_ui/base_model.py
index c9177fc9..52f07626 100644
--- a/zhenxun/builtin_plugins/web_ui/base_model.py
+++ b/zhenxun/builtin_plugins/web_ui/base_model.py
@@ -31,7 +31,7 @@ class Result(Generic[RT], BaseModel):
"""info"""
warning: str | None = None
"""警告信息"""
- data: RT = None
+ data: RT | None = None
"""返回数据"""
@classmethod
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/common_utils.py b/zhenxun/utils/common_utils.py
index 76445649..61259bd8 100644
--- a/zhenxun/utils/common_utils.py
+++ b/zhenxun/utils/common_utils.py
@@ -1,3 +1,5 @@
+from typing import overload
+
from nonebot.adapters import Bot
from nonebot_plugin_uninfo import Session, SupportScope, Uninfo, get_interface
@@ -62,6 +64,34 @@ class CommonUtils:
return True
return False
+ @staticmethod
+ def format(name: str) -> str:
+ return f"<{name},"
+
+ @overload
+ @classmethod
+ def convert_module_format(cls, data: str) -> list[str]: ...
+
+ @overload
+ @classmethod
+ def convert_module_format(cls, data: list[str]) -> str: ...
+
+ @classmethod
+ def convert_module_format(cls, data: str | list[str]) -> str | list[str]:
+ """
+ 在 ` UserData | None:
"""获取用户信息
参数:
bot: Bot
user_id: 用户id
- group_id: 群组/频道id.
+ group_id: 群组id.
+ channel_id: 频道id.
返回:
UserData | None: 用户数据
"""
- if isinstance(bot, v11Bot):
- if group_id:
- if user := await bot.get_group_member_info(
- group_id=int(group_id), user_id=int(user_id)
- ):
- return UserData(
- name=user["nickname"],
- card=user["card"],
- user_id=user["user_id"],
- group_id=user["group_id"],
- role=user["role"],
- join_time=user["join_time"],
- )
- elif friend_list := await bot.get_friend_list():
- for f in friend_list:
- if f["user_id"] == int(user_id):
- return UserData(
- name=f["nickname"],
- card=f["remark"],
- user_id=f["user_id"],
- )
- if isinstance(bot, v12Bot):
- if group_id:
- if user := await bot.get_group_member_info(
- group_id=group_id, user_id=user_id
- ):
- return UserData(
- name=user["user_name"],
- card=user["user_displayname"],
- user_id=user["user_id"],
- group_id=group_id,
- )
- elif friend_list := await bot.get_friend_list():
- for f in friend_list:
- if f["user_id"] == int(user_id):
- return UserData(
- name=f["user_name"],
- card=f["user_remark"],
- user_id=f["user_id"],
- )
- if isinstance(bot, DodoBot) and group_id:
- if user := await bot.get_member_info(
- island_source_id=group_id, dodo_source_id=user_id
- ):
- return UserData(
- name=user.nick_name,
- card=user.personal_nick_name,
- avatar_url=user.avatar_url,
- user_id=user.dodo_source_id,
- group_id=user.island_source_id,
- join_time=int(user.join_time.timestamp()),
+ if interface := get_interface(bot):
+ member = None
+ user = None
+ if channel_id:
+ member = await interface.get_member(
+ SceneType.CHANNEL_TEXT, channel_id, user_id
)
- if isinstance(bot, KaiheilaBot) and group_id:
- if user := await bot.user_view(guild_id=group_id, user_id=user_id):
- second = int(user.joined_at / 1000) if user.joined_at else None
+ if member:
+ user = member.user
+ elif group_id:
+ member = await interface.get_member(SceneType.GROUP, group_id, user_id)
+ if member:
+ user = member.user
+ else:
+ user = await interface.get_user(user_id)
+ if not user:
+ return None
+ if member:
return UserData(
- name=user.nickname or "",
- avatar_url=user.avatar,
- user_id=user_id,
+ name=user.name or "",
+ card=member.nick,
+ user_id=user.id,
group_id=group_id,
- join_time=second,
+ channel_id=channel_id,
+ role=member.role.id if member.role else None,
+ join_time=int(member.joined_at.timestamp())
+ if member.joined_at
+ else None,
+ )
+ else:
+ return UserData(
+ name=user.name or "",
+ user_id=user.id,
+ group_id=group_id,
+ channel_id=channel_id,
)
return None
@@ -337,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)
@@ -361,7 +292,9 @@ class PlatformUtils:
group_list, platform = await cls.get_group_list(bot)
if group_list:
db_group = await GroupConsole.all()
- db_group_id = [(group.group_id, group.channel_id) for group in db_group]
+ db_group_id: list[tuple[str, str]] = [
+ (group.group_id, group.channel_id) for group in db_group
+ ]
for group in group_list:
group.platform = platform
if (group.group_id, group.channel_id) not in db_group_id:
@@ -411,69 +344,43 @@ class PlatformUtils:
return "unknown"
@classmethod
- async def get_group_list(cls, bot: Bot) -> tuple[list[GroupConsole], str]:
+ async def get_group_list(
+ cls, bot: Bot, only_group: bool = False
+ ) -> tuple[list[GroupConsole], str]:
"""获取群组列表
参数:
bot: Bot
+ only_group: 是否只获取群组(不获取channel)
返回:
tuple[list[GroupConsole], str]: 群组列表, 平台
"""
- if isinstance(bot, v11Bot):
- group_list = await bot.get_group_list()
- return [
- GroupConsole(
- group_id=str(g["group_id"]),
- group_name=g["group_name"],
- max_member_count=g["max_member_count"],
- member_count=g["member_count"],
- )
- for g in group_list
- ], "qq"
- if isinstance(bot, v12Bot):
- group_list = await bot.get_group_list()
- return [
- GroupConsole(
- group_id=g.group_id, # type: ignore
- user_name=g.group_name, # type: ignore
- )
- for g in group_list
- ], "qq"
- if isinstance(bot, DodoBot):
- island_list = await bot.get_island_list()
- source_id_list = [
- (g.island_source_id, g.island_name)
- for g in island_list
- if g.island_source_id
- ]
- group_list = []
- for id, name in source_id_list:
- channel_list = await bot.get_channel_list(island_source_id=id)
- group_list.append(GroupConsole(group_id=id, group_name=name))
- group_list += [
+ if interface := get_interface(bot):
+ platform = cls.get_platform(bot)
+ result_list = []
+ scenes = await interface.get_scenes(SceneType.GROUP)
+ for scene in scenes:
+ group_id = scene.id
+ result_list.append(
GroupConsole(
- group_id=id, group_name=c.channel_name, channel_id=c.channel_id
+ group_id=scene.id,
+ group_name=scene.name,
)
- for c in channel_list
- ]
- return group_list, "dodo"
- if isinstance(bot, KaiheilaBot):
- group_list = []
- guilds = await bot.guild_list()
- if guilds.guilds:
- for guild_id, name in [(g.id_, g.name) for g in guilds.guilds if g.id_]:
- view = await bot.guild_view(guild_id=guild_id)
- group_list.append(GroupConsole(group_id=guild_id, group_name=name))
- if view.channels:
- group_list += [
- GroupConsole(
- group_id=guild_id, group_name=c.name, channel_id=c.id_
+ )
+ if not only_group and platform != "qq":
+ if channel_list := await interface.get_scenes(
+ parent_scene_id=group_id
+ ):
+ for channel in channel_list:
+ result_list.append(
+ GroupConsole(
+ group_id=scene.id,
+ group_name=channel.name,
+ channel_id=channel.id,
+ )
)
- for c in view.channels
- if c.type != 0
- ]
- return group_list, "kaiheila"
+ return result_list, platform
return [], ""
@classmethod
@@ -508,36 +415,17 @@ class PlatformUtils:
返回:
list[FriendUser]: 好友列表
"""
- if isinstance(bot, v11Bot):
- friend_list = await bot.get_friend_list()
+ if interface := get_interface(bot):
+ user_list = await interface.get_users()
return [
- FriendUser(user_id=str(f["user_id"]), user_name=f["nickname"])
- for f in friend_list
- ], "qq"
- if isinstance(bot, v12Bot):
- friend_list = await bot.get_friend_list()
- return [
- FriendUser(
- user_id=f.user_id, # type: ignore
- user_name=f.user_displayname or f.user_remark or f.user_name, # type: ignore
- )
- for f in friend_list
- ], "qq"
- # if isinstance(bot, DodoBot):
- # # TODO: dodo好友列表
- # pass
- # if isinstance(bot, KaiheilaBot):
- # # TODO: kaiheila好友列表
- # pass
- # if isinstance(bot, DiscordBot):
- # # TODO: discord好友列表
- # pass
+ FriendUser(user_id=u.id, user_name=u.name) for u in user_list
+ ], cls.get_platform(bot)
return [], ""
@classmethod
def get_target(
cls,
- bot: Bot,
+ *,
user_id: str | None = None,
group_id: str | None = None,
channel_id: str | None = None,
@@ -554,16 +442,12 @@ class PlatformUtils:
target: 对应平台Target
"""
target = None
- if isinstance(bot, v11Bot | v12Bot):
- if group_id:
- target = Target(group_id)
- elif user_id:
- target = Target(user_id, private=True)
- elif isinstance(bot, DodoBot | KaiheilaBot):
- if group_id and channel_id:
- target = Target(channel_id, parent_id=group_id, channel=True)
- elif user_id:
- target = Target(user_id, private=True)
+ if group_id and channel_id:
+ target = Target(channel_id, parent_id=group_id, channel=True)
+ elif group_id:
+ target = Target(group_id)
+ elif user_id:
+ target = Target(user_id, private=True)
return target
@@ -646,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)