mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-03 10:40:02 +08:00
版本更新 (#1666)
* ✨ 父级插件加载 * ✅ 添加测试:更新与添加插件 (#1594) * ✅ 测试更新与添加插件 * ✅ Sourcery建议 * 👷 添加pytest * 🎨 优化代码 * 🐛 bug修复 * 🐛修复添加插件返回403的问题 (#1595) * 完善测试方法 * vscode测试配置 * 重构插件安装过程 * 🎨 修改readme * Update README.md * 🐛 修改bug与版本锁定 * 🐛 修复超级用户对群组功能开关 * 🐛 修复插件商店检查插件更新问题 (#1597) * 🐛 修复插件商店检查插件更新问题 * 🐛 恶意命令检测问题 * 🐛 增加插件状态检查 (#1598) * ✅ 优化测试用例 * 🐛 更改插件更新与安装逻辑 * 🐛 修复更新群组成员信息 * 🎨 代码优化 * 🚀 更新Dockerfile (#1599) * 🎨 更新requirements * ➕ 添加依赖aiocache * ⚡ 添加github镜像 * ✨ 添加仓库目录多获取渠道 * 🐛 修复测试用例 * ✨ 添加API缓存 * 🎨 采取Sourcery建议 * 🐛 文件下载逻辑修改 * 🎨 优化代码 * 🐛 修复插件开关有时出现错误 * ✨ 重构自检ui * 🐛 自检html修正 * 修复签到逻辑bug,并使代码更灵活以适应签到好感度等级配置 (#1606) * 修复签到功能已知问题 * 修复签到功能已知问题 * 修改参数名称 * 修改uid判断 --------- Co-authored-by: HibiKier <45528451+HibiKier@users.noreply.github.com> * 🎨 代码结构优化 * 🐛 私聊时修改插件时删除私聊帮助 * 🐛 过滤父插件 * 🐛 修复自检在ARM上的问题 (#1607) * 🐛 修复自检在ARM上的问题 * ✅ 优化测试 * ✨ 支持mysql,psql,sqlite随机函数 * 🔧 VSCode配置修改 * 🔧 VSCode配置修改 * ✨ 添加金币排行 Co-Authored-By: HibiKier <45528451+HibiKier@users.noreply.github.com> * 📝 修改README Co-Authored-By: HibiKier <45528451+HibiKier@users.noreply.github.com> * 🔨 提取GitHub相关操作 (#1609) * 🔨 提取GitHub相关操作 * 🔨 重构API策略 * ✨ 签到/金币排行限制最大数量 (#1616) * ✨ 签到/金币排行限制最大数量 * 🐛 修复超级用户id获取问题 * 🐛 修复路径解压与挂载 (#1619) * 🐛 修复功能少时zhenxun帮助图片排序问题 (#1620) * 🐛 签到文本适应 (#1622) * 🐛 好感度排行提供默认值 (#1624) * 🎈 优先使用github api (#1625) * ✨ 重构帮助,限制普通用户查询管理插件 (#1626) * 🐛 修复群权限与插件等级匹配 (#1627) * ✨ 当管理员尝试ban真寻时将被反杀 (#1628) * ✨ 群组发言时间检测提供开关配置 (#1630) * 🐳 chore: 支持自动修改版本号 (#1629) * 🎈 perf(github_utils): 支持github url下载遍历 (#1632) * 🎈 perf(github_utils): 支持github url下载遍历 * 🐞 fix(http_utils): 修复一些下载问题 * 🦄 refactor(http_utils): 部分重构 * chore(version): Update version to v0.2.2-e6f17c4 --------- Co-authored-by: AkashiCoin <AkashiCoin@users.noreply.github.com> * 🧪 test(auto_update): 修复测试用例 (#1633) * 🐛 修复商店商品为空时报错 (#1634) * 🐛 修复群权限与插件等级匹配 (#1635) * ✨ message_build支持AtAll (#1639) * 🎈 perf: 使用commit号下载插件 (#1641) * 🎈 perf: 使用commit号下载插件 * chore(version): Update version to v0.2.2-f9c7360 --------- Co-authored-by: AkashiCoin <AkashiCoin@users.noreply.github.com> * 🐳 chore: 修改运行检查触发路径 (#1642) * 🐳 chore: 修改运行检查触发路径 * 🐳 chore: 添加tests目录 * ✨ 重构qq群事件处理 (#1643) * 🐛 签到名称自适应 (#1644) * 🎨 更新README (#1645) * 🐛 fix(http_utils): 流式下载Content-Length错误 (#1647) * 🐛 修复群组中帮助功能状态显示问题 (#1650) * 🐛 修复群欢迎消息设置 (#1651) * 🐛 修复webui下载后首次启动错误 (#1652) * 🐛 修复webui下载后首次启动错误 * chore(version): Update version to v0.2.2-4a8ef85 --------- Co-authored-by: HibiKier <HibiKier@users.noreply.github.com> * ✨ 移除默认图片文件夹:爬 (#1653) * ✨ 安装/移除插件提供插件安装/卸载方法用于插件初始化 (#1654) * ✨ 新增超级用户与管理员帮助模板 (#1655) * ✨ 新增个人信息命令 (#1657) * ✨ 修改个人信息菜单名称 (#1658) * ✨ 新增插件商店api (#1659) * ✨ 新增插件商店api * chore(version): Update version to v0.2.2-7e15f20 --------- Co-authored-by: HibiKier <HibiKier@users.noreply.github.com> * ✨ 将cd,block,count限制复原配置文件 (#1662) * 🎨 修改README (#1663) * 🎨 修改版本号 (#1664) * 🎨 修改requirements (#1665) --------- Co-authored-by: AkashiCoin <l1040186796@gmail.com> Co-authored-by: fanyinrumeng <42991257+fanyinrumeng@users.noreply.github.com> Co-authored-by: AkashiCoin <i@loli.vet> Co-authored-by: Elaga <1728903318@qq.com> Co-authored-by: AkashiCoin <AkashiCoin@users.noreply.github.com> Co-authored-by: HibiKier <HibiKier@users.noreply.github.com>
This commit is contained in:
co-authored by
AkashiCoin
HibiKier
AkashiCoin
fanyinrumeng
AkashiCoin
Elaga
parent
daa40ae8b8
commit
4e33bf3a50
@@ -39,5 +39,5 @@ async def _(bot: Bot):
|
||||
await GroupConsole.filter(group_id__in=update_id).update(group_flag=1)
|
||||
logger.debug(
|
||||
f"更新Bot: {bot.self_id} 的群认证完成,共创建 {len(create_list)} 条数据,"
|
||||
"共修改 {len(update_id)} 条数据..."
|
||||
f"共修改 {len(update_id)} 条数据..."
|
||||
)
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
from pathlib import Path
|
||||
|
||||
import nonebot
|
||||
from nonebot import get_loaded_plugins
|
||||
from nonebot.drivers import Driver
|
||||
from nonebot.plugin import Plugin
|
||||
from ruamel.yaml import YAML
|
||||
from nonebot.plugin import Plugin
|
||||
from nonebot.drivers import Driver
|
||||
from nonebot import get_loaded_plugins
|
||||
from ruamel.yaml.comments import CommentedMap
|
||||
|
||||
from zhenxun.configs.config import Config
|
||||
from zhenxun.configs.path_config import DATA_PATH
|
||||
from zhenxun.configs.utils import RegisterConfig
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.configs.config import Config
|
||||
from zhenxun.configs.utils import RegisterConfig
|
||||
from zhenxun.configs.path_config import DATA_PATH
|
||||
|
||||
_yaml = YAML(pure=True)
|
||||
_yaml.allow_unicode = True
|
||||
@@ -72,15 +72,14 @@ def _generate_simple_config():
|
||||
Config.set_config(module, k, _data[module][k])
|
||||
_tmp_data[module][k] = Config.get_config(module, k)
|
||||
except AttributeError as e:
|
||||
raise AttributeError(f"{e}\n" + "可能为config.yaml配置文件填写不规范")
|
||||
raise AttributeError(f"{e}\n可能为config.yaml配置文件填写不规范") from e
|
||||
Config.save()
|
||||
temp_file = DATA_PATH / "temp_config.yaml"
|
||||
# 重新生成简易配置文件
|
||||
try:
|
||||
with open(temp_file, "w", encoding="utf8") as wf:
|
||||
# yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
|
||||
_yaml.dump(_tmp_data, wf)
|
||||
with open(temp_file, "r", encoding="utf8") as rf:
|
||||
with open(temp_file, encoding="utf8") as rf:
|
||||
_data = _yaml.load(rf)
|
||||
# 添加注释
|
||||
for module in _data.keys():
|
||||
@@ -93,7 +92,7 @@ def _generate_simple_config():
|
||||
with SIMPLE_CONFIG_FILE.open("w", encoding="utf8") as wf:
|
||||
_yaml.dump(_data, wf)
|
||||
except Exception as e:
|
||||
logger.error(f"生成简易配置注释错误...", e=e)
|
||||
logger.error("生成简易配置注释错误...", e=e)
|
||||
if temp_file.exists():
|
||||
temp_file.unlink()
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@ import nonebot
|
||||
import aiofiles
|
||||
import ujson as json
|
||||
from ruamel.yaml import YAML
|
||||
from nonebot.plugin import Plugin
|
||||
from nonebot.drivers import Driver
|
||||
from nonebot import get_loaded_plugins
|
||||
from nonebot.plugin import Plugin, PluginMetadata
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.models.task_info import TaskInfo
|
||||
@@ -21,6 +21,8 @@ from zhenxun.utils.enum import (
|
||||
PluginLimitType,
|
||||
)
|
||||
|
||||
from .manager import manager
|
||||
|
||||
_yaml = YAML(pure=True)
|
||||
_yaml.allow_unicode = True
|
||||
_yaml.indent = 2
|
||||
@@ -41,64 +43,68 @@ async def _handle_setting(
|
||||
plugin_list: 插件列表
|
||||
limit_list: 插件限制列表
|
||||
"""
|
||||
if metadata := plugin.metadata:
|
||||
extra = metadata.extra
|
||||
extra_data = PluginExtraData(**extra)
|
||||
logger.debug(f"{metadata.name}:{plugin.name} -> {extra}", "初始化插件数据")
|
||||
setting = extra_data.setting or PluginSetting()
|
||||
if metadata.type == "library":
|
||||
extra_data.plugin_type = PluginType.HIDDEN
|
||||
if (
|
||||
extra_data.plugin_type
|
||||
== PluginType.HIDDEN
|
||||
# and extra_data.plugin_type != "功能"
|
||||
):
|
||||
extra_data.menu_type = ""
|
||||
plugin_list.append(
|
||||
PluginInfo(
|
||||
metadata = plugin.metadata
|
||||
if not metadata:
|
||||
if not plugin.sub_plugins:
|
||||
return
|
||||
"""父插件"""
|
||||
metadata = PluginMetadata(name=plugin.name, description="", usage="")
|
||||
extra = metadata.extra
|
||||
extra_data = PluginExtraData(**extra)
|
||||
logger.debug(f"{metadata.name}:{plugin.name} -> {extra}", "初始化插件数据")
|
||||
setting = extra_data.setting or PluginSetting()
|
||||
if metadata.type == "library":
|
||||
extra_data.plugin_type = PluginType.HIDDEN
|
||||
if extra_data.plugin_type == PluginType.HIDDEN:
|
||||
extra_data.menu_type = ""
|
||||
if plugin.sub_plugins:
|
||||
extra_data.plugin_type = PluginType.PARENT
|
||||
plugin_list.append(
|
||||
PluginInfo(
|
||||
module=plugin.name,
|
||||
module_path=plugin.module_name,
|
||||
name=metadata.name,
|
||||
author=extra_data.author,
|
||||
version=extra_data.version,
|
||||
level=setting.level,
|
||||
default_status=setting.default_status,
|
||||
limit_superuser=setting.limit_superuser,
|
||||
menu_type=extra_data.menu_type,
|
||||
cost_gold=setting.cost_gold,
|
||||
plugin_type=extra_data.plugin_type,
|
||||
admin_level=extra_data.admin_level,
|
||||
parent=(plugin.parent_plugin.module_name if plugin.parent_plugin else None),
|
||||
)
|
||||
)
|
||||
if extra_data.limits:
|
||||
limit_list.extend(
|
||||
PluginLimit(
|
||||
module=plugin.name,
|
||||
module_path=plugin.module_name,
|
||||
name=metadata.name,
|
||||
author=extra_data.author,
|
||||
version=extra_data.version,
|
||||
level=setting.level,
|
||||
default_status=setting.default_status,
|
||||
limit_superuser=setting.limit_superuser,
|
||||
menu_type=extra_data.menu_type,
|
||||
cost_gold=setting.cost_gold,
|
||||
plugin_type=extra_data.plugin_type,
|
||||
admin_level=extra_data.admin_level,
|
||||
limit_type=limit._type,
|
||||
watch_type=limit.watch_type,
|
||||
status=limit.status,
|
||||
check_type=limit.check_type,
|
||||
result=limit.result,
|
||||
cd=getattr(limit, "cd", None),
|
||||
max_count=getattr(limit, "max_count", None),
|
||||
)
|
||||
for limit in extra_data.limits
|
||||
)
|
||||
if extra_data.limits:
|
||||
limit_list.extend(
|
||||
PluginLimit(
|
||||
module=plugin.name,
|
||||
module_path=plugin.module_name,
|
||||
limit_type=limit._type,
|
||||
watch_type=limit.watch_type,
|
||||
status=limit.status,
|
||||
check_type=limit.check_type,
|
||||
result=limit.result,
|
||||
cd=getattr(limit, "cd", None),
|
||||
max_count=getattr(limit, "max_count", None),
|
||||
)
|
||||
for limit in extra_data.limits
|
||||
)
|
||||
if extra_data.tasks:
|
||||
task_list.extend(
|
||||
(
|
||||
task.create_status,
|
||||
TaskInfo(
|
||||
module=task.module,
|
||||
name=task.name,
|
||||
status=task.status,
|
||||
run_time=task.run_time,
|
||||
default_status=task.default_status,
|
||||
),
|
||||
)
|
||||
for task in extra_data.tasks
|
||||
if extra_data.tasks:
|
||||
task_list.extend(
|
||||
(
|
||||
task.create_status,
|
||||
TaskInfo(
|
||||
module=task.module,
|
||||
name=task.name,
|
||||
status=task.status,
|
||||
run_time=task.run_time,
|
||||
default_status=task.default_status,
|
||||
),
|
||||
)
|
||||
for task in extra_data.tasks
|
||||
)
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
@@ -115,8 +121,7 @@ async def _():
|
||||
module2id = {m["module_path"]: m["id"] for m in module_list}
|
||||
for plugin in get_loaded_plugins():
|
||||
load_plugin.append(plugin.module_name)
|
||||
if plugin.metadata:
|
||||
await _handle_setting(plugin, plugin_list, limit_list, task_list)
|
||||
await _handle_setting(plugin, plugin_list, limit_list, task_list)
|
||||
create_list = []
|
||||
update_list = []
|
||||
for plugin in plugin_list:
|
||||
@@ -145,23 +150,25 @@ async def _():
|
||||
# ["name", "author", "version", "admin_level", "plugin_type"],
|
||||
# 10,
|
||||
# )
|
||||
if limit_list:
|
||||
limit_create = []
|
||||
plugins = []
|
||||
if module_path_list := [limit.module_path for limit in limit_list]:
|
||||
plugins = await PluginInfo.filter(module_path__in=module_path_list).all()
|
||||
if plugins:
|
||||
for limit in limit_list:
|
||||
if lmt := [p for p in plugins if p.module_path == limit.module_path]:
|
||||
plugin = lmt[0]
|
||||
limit_type_list = [
|
||||
_limit.limit_type for _limit in await plugin.plugin_limit.all() # type: ignore
|
||||
]
|
||||
if limit.limit_type not in limit_type_list:
|
||||
limit.plugin = plugin
|
||||
limit_create.append(limit)
|
||||
if limit_create:
|
||||
await PluginLimit.bulk_create(limit_create, 10)
|
||||
# for limit in limit_list:
|
||||
# limit_create = []
|
||||
# plugins = []
|
||||
# if module_path_list := [limit.module_path for limit in limit_list]:
|
||||
# plugins = await PluginInfo.get_plugins(module_path__in=module_path_list)
|
||||
# if plugins:
|
||||
# for limit in limit_list:
|
||||
# if lmt := [p for p in plugins if p.module_path == limit.module_path]:
|
||||
# plugin = lmt[0]
|
||||
# """不在数据库中"""
|
||||
# limit_type_list = [
|
||||
# _limit.limit_type
|
||||
# for _limit in await plugin.plugin_limit.all() # type: ignore
|
||||
# ]
|
||||
# if limit.limit_type not in limit_type_list:
|
||||
# limit.plugin = plugin
|
||||
# limit_create.append(limit)
|
||||
# if limit_create:
|
||||
# await PluginLimit.bulk_create(limit_create, 10)
|
||||
if task_list:
|
||||
module_dict = {
|
||||
t[1]: t[0] for t in await TaskInfo.all().values_list("id", "module")
|
||||
@@ -192,10 +199,18 @@ async def _():
|
||||
await data_migration()
|
||||
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:
|
||||
if not manager.exist(limit.module_path, limit.limit_type):
|
||||
"""不存在,添加"""
|
||||
manager.add(limit.module_path, limit)
|
||||
manager.save_file()
|
||||
await manager.load_to_db()
|
||||
|
||||
|
||||
async def data_migration():
|
||||
await limit_migration()
|
||||
# await limit_migration()
|
||||
await plugin_migration()
|
||||
await group_migration()
|
||||
|
||||
|
||||
@@ -0,0 +1,417 @@
|
||||
from copy import deepcopy
|
||||
|
||||
from ruamel.yaml import YAML
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.configs.path_config import DATA_PATH
|
||||
from zhenxun.models.plugin_info import PluginInfo
|
||||
from zhenxun.models.plugin_limit import PluginLimit
|
||||
from zhenxun.utils.enum import BlockType, LimitCheckType, PluginLimitType
|
||||
from zhenxun.configs.utils import BaseBlock, PluginCdBlock, PluginCountBlock
|
||||
|
||||
_yaml = YAML(pure=True)
|
||||
_yaml.indent = 2
|
||||
_yaml.allow_unicode = True
|
||||
|
||||
|
||||
CD_TEST = """需要cd的功能
|
||||
自定义的功能需要cd也可以在此配置
|
||||
key:模块名称
|
||||
cd:cd 时长(秒)
|
||||
status:此限制的开关状态
|
||||
check_type:'PRIVATE'/'GROUP'/'ALL',限制私聊/群聊/全部
|
||||
watch_type:监听对象,以user_id或group_id作为键来限制,'USER':用户id,'GROUP':群id
|
||||
示例:'USER':用户N秒内触发1次,'GROUP':群N秒内触发1次
|
||||
result:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
|
||||
result 为 "" 或 None 时则不回复
|
||||
result示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
|
||||
result回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
|
||||
用户昵称↑ 昵称系统的昵称↑ 艾特用户↑"""
|
||||
|
||||
|
||||
BLOCK_TEST = """用户调用阻塞
|
||||
即 当用户调用此功能还未结束时
|
||||
用发送消息阻止用户重复调用此命令直到该命令结束
|
||||
key:模块名称
|
||||
status:此限制的开关状态
|
||||
check_type:'PRIVATE'/'GROUP'/'ALL',限制私聊/群聊/全部
|
||||
watch_type:监听对象,以user_id或group_id作为键来限制,'USER':用户id,'GROUP':群id
|
||||
示例:'USER':阻塞用户,'group':阻塞群聊
|
||||
result:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
|
||||
result 为 "" 或 None 时则不回复
|
||||
result示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
|
||||
result回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
|
||||
用户昵称↑ 昵称系统的昵称↑ 艾特用户↑"""
|
||||
|
||||
COUNT_TEST = """命令每日次数限制
|
||||
即 用户/群聊 每日可调用命令的次数 [数据内存存储,重启将会重置]
|
||||
每日调用直到 00:00 刷新
|
||||
key:模块名称
|
||||
max_count: 每日调用上限
|
||||
status:此限制的开关状态
|
||||
watch_type:监听对象,以user_id或group_id作为键来限制,'USER':用户id,'GROUP':群id
|
||||
示例:'USER':用户上限,'group':群聊上限
|
||||
result:回复的话,可以添加[at],[uname],[nickname]来对应艾特,用户群名称,昵称系统昵称
|
||||
result 为 "" 或 None 时则不回复
|
||||
result示例:"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
|
||||
result回复:"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
|
||||
用户昵称↑ 昵称系统的昵称↑ 艾特用户↑"""
|
||||
|
||||
|
||||
class Manager:
|
||||
"""
|
||||
插件命令 cd 管理器
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.cd_file = DATA_PATH / "configs" / "plugins2cd.yaml"
|
||||
self.block_file = DATA_PATH / "configs" / "plugins2block.yaml"
|
||||
self.count_file = DATA_PATH / "configs" / "plugins2count.yaml"
|
||||
self.cd_data = {}
|
||||
self.block_data = {}
|
||||
self.count_data = {}
|
||||
|
||||
def add(
|
||||
self,
|
||||
module_path: str,
|
||||
data: BaseBlock | PluginCdBlock | PluginCountBlock | PluginLimit,
|
||||
):
|
||||
"""添加限制"""
|
||||
if isinstance(data, PluginLimit):
|
||||
check_type = BlockType.ALL
|
||||
if LimitCheckType.GROUP == data.check_type:
|
||||
check_type = BlockType.GROUP
|
||||
elif LimitCheckType.PRIVATE == data.check_type:
|
||||
check_type = BlockType.PRIVATE
|
||||
if data.limit_type == PluginLimitType.CD:
|
||||
data = PluginCdBlock(
|
||||
status=data.status,
|
||||
check_type=check_type,
|
||||
watch_type=data.watch_type,
|
||||
result=data.result,
|
||||
cd=data.cd,
|
||||
)
|
||||
elif data.limit_type == PluginLimitType.BLOCK:
|
||||
data = BaseBlock(
|
||||
status=data.status,
|
||||
check_type=check_type,
|
||||
watch_type=data.watch_type,
|
||||
result=data.result,
|
||||
)
|
||||
elif data.limit_type == PluginLimitType.COUNT:
|
||||
data = PluginCountBlock(
|
||||
status=data.status,
|
||||
watch_type=data.watch_type,
|
||||
result=data.result,
|
||||
max_count=data.max_count,
|
||||
)
|
||||
if isinstance(data, PluginCdBlock):
|
||||
self.cd_data[module_path] = data
|
||||
elif isinstance(data, PluginCountBlock):
|
||||
self.count_data[module_path] = data
|
||||
elif isinstance(data, BaseBlock):
|
||||
self.block_data[module_path] = data
|
||||
|
||||
def exist(self, module_path: str, type: PluginLimitType):
|
||||
"""是否存在"""
|
||||
if type == PluginLimitType.CD:
|
||||
return module_path in self.cd_data
|
||||
elif type == PluginLimitType.BLOCK:
|
||||
return module_path in self.block_data
|
||||
elif type == PluginLimitType.COUNT:
|
||||
return module_path in self.count_data
|
||||
|
||||
def init(self):
|
||||
if not self.cd_file.exists():
|
||||
self.save_cd_file()
|
||||
if not self.block_file.exists():
|
||||
self.save_block_file()
|
||||
if not self.count_file.exists():
|
||||
self.save_count_file()
|
||||
self.__load_file()
|
||||
|
||||
def __load_file(self):
|
||||
self.__load_block_file()
|
||||
self.__load_cd_file()
|
||||
self.__load_count_file()
|
||||
|
||||
def save_file(self):
|
||||
"""保存文件"""
|
||||
self.save_cd_file()
|
||||
self.save_block_file()
|
||||
self.save_count_file()
|
||||
|
||||
def save_cd_file(self):
|
||||
"""保存文件"""
|
||||
self._extracted_from_save_file_3("PluginCdLimit", CD_TEST, self.cd_data)
|
||||
|
||||
def save_block_file(self):
|
||||
"""保存文件"""
|
||||
self._extracted_from_save_file_3(
|
||||
"PluginBlockLimit", BLOCK_TEST, self.block_data
|
||||
)
|
||||
|
||||
def save_count_file(self):
|
||||
"""保存文件"""
|
||||
self._extracted_from_save_file_3(
|
||||
"PluginCountLimit", COUNT_TEST, self.count_data
|
||||
)
|
||||
|
||||
def _extracted_from_save_file_3(self, type_: str, after: str, data: dict):
|
||||
"""保存文件
|
||||
|
||||
参数:
|
||||
type_: 类型参数
|
||||
after: 备注
|
||||
"""
|
||||
temp_data = deepcopy(data)
|
||||
if not temp_data:
|
||||
temp_data = {
|
||||
"test": {
|
||||
"status": False,
|
||||
"check_type": "ALL",
|
||||
"limit_type": "USER",
|
||||
"result": "你冲的太快了,请稍后再冲",
|
||||
}
|
||||
}
|
||||
if type_ == "PluginCdLimit":
|
||||
temp_data["test"]["cd"] = 5
|
||||
elif type_ == "PluginCountLimit":
|
||||
temp_data["test"]["max_count"] = 5
|
||||
del temp_data["test"]["check_type"]
|
||||
else:
|
||||
for v in temp_data:
|
||||
temp_data[v] = temp_data[v].dict()
|
||||
if check_type := temp_data[v].get("check_type"):
|
||||
temp_data[v]["check_type"] = str(check_type)
|
||||
if watch_type := temp_data[v].get("watch_type"):
|
||||
temp_data[v]["watch_type"] = str(watch_type)
|
||||
if type_ == "PluginCountLimit":
|
||||
del temp_data[v]["check_type"]
|
||||
file = self.block_file
|
||||
if type_ == "PluginCdLimit":
|
||||
file = self.cd_file
|
||||
elif type_ == "PluginCountLimit":
|
||||
file = self.count_file
|
||||
with open(file, "w", encoding="utf8") as f:
|
||||
_yaml.dump({type_: temp_data}, f)
|
||||
with open(file, encoding="utf8") as rf:
|
||||
_data = _yaml.load(rf)
|
||||
_data.yaml_set_comment_before_after_key(after=after, key=type_)
|
||||
with open(file, "w", encoding="utf8") as wf:
|
||||
_yaml.dump(_data, wf)
|
||||
|
||||
def __load_cd_file(self):
|
||||
self.cd_data: dict[str, PluginCdBlock] = {}
|
||||
if self.cd_file.exists():
|
||||
with open(self.cd_file, encoding="utf8") as f:
|
||||
temp = _yaml.load(f)
|
||||
if "PluginCdLimit" in temp.keys():
|
||||
for k, v in temp["PluginCdLimit"].items():
|
||||
self.cd_data[k] = PluginCdBlock.parse_obj(v)
|
||||
|
||||
def __load_block_file(self):
|
||||
self.block_data: dict[str, BaseBlock] = {}
|
||||
if self.block_file.exists():
|
||||
with open(self.block_file, encoding="utf8") as f:
|
||||
temp = _yaml.load(f)
|
||||
if "PluginBlockLimit" in temp.keys():
|
||||
for k, v in temp["PluginBlockLimit"].items():
|
||||
self.block_data[k] = BaseBlock.parse_obj(v)
|
||||
|
||||
def __load_count_file(self):
|
||||
self.count_data: dict[str, PluginCountBlock] = {}
|
||||
if self.count_file.exists():
|
||||
with open(self.count_file, encoding="utf8") as f:
|
||||
temp = _yaml.load(f)
|
||||
if "PluginCountLimit" in temp.keys():
|
||||
for k, v in temp["PluginCountLimit"].items():
|
||||
self.count_data[k] = PluginCountBlock.parse_obj(v)
|
||||
|
||||
def __replace_data(
|
||||
self,
|
||||
db_data: PluginLimit | None,
|
||||
limit: PluginCdBlock | BaseBlock | PluginCountBlock,
|
||||
) -> PluginLimit:
|
||||
"""替换数据"""
|
||||
if not db_data:
|
||||
db_data = PluginLimit()
|
||||
db_data.status = limit.status
|
||||
check_type = LimitCheckType.ALL
|
||||
if BlockType.GROUP == limit.check_type:
|
||||
check_type = LimitCheckType.GROUP
|
||||
elif BlockType.PRIVATE == limit.check_type:
|
||||
check_type = LimitCheckType.PRIVATE
|
||||
db_data.check_type = check_type
|
||||
db_data.watch_type = limit.watch_type
|
||||
db_data.result = limit.result or ""
|
||||
return db_data
|
||||
|
||||
def __set_data(
|
||||
self,
|
||||
k: str,
|
||||
db_data: PluginLimit | None,
|
||||
limit: PluginCdBlock | BaseBlock | PluginCountBlock,
|
||||
limit_type: PluginLimitType,
|
||||
module2plugin: dict[str, PluginInfo],
|
||||
) -> tuple[PluginLimit, bool]:
|
||||
"""设置数据
|
||||
|
||||
参数:
|
||||
k: 模块名
|
||||
db_data: 数据库数据
|
||||
limit: 文件数据
|
||||
limit_type: 限制类型
|
||||
module2plugin: 模块:插件信息
|
||||
|
||||
返回:
|
||||
tuple[PluginLimit, bool]: PluginLimit,是否创建
|
||||
"""
|
||||
if not db_data:
|
||||
return (
|
||||
PluginLimit(
|
||||
module=k.split(".")[-1],
|
||||
module_path=k,
|
||||
limit_type=limit_type,
|
||||
plugin=module2plugin.get(k),
|
||||
cd=getattr(limit, "cd", None),
|
||||
max_count=getattr(limit, "max_count", None),
|
||||
status=limit.status,
|
||||
check_type=limit.check_type,
|
||||
watch_type=limit.watch_type,
|
||||
result=limit.result,
|
||||
),
|
||||
True,
|
||||
)
|
||||
db_data = self.__replace_data(db_data, limit)
|
||||
if limit_type == PluginLimitType.CD:
|
||||
db_data.cd = limit.cd # type: ignore
|
||||
if limit_type == PluginLimitType.COUNT:
|
||||
db_data.max_count = limit.max_count # type: ignore
|
||||
return db_data, False
|
||||
|
||||
def __get_file_data(self, limit_type: PluginLimitType) -> dict:
|
||||
"""获取文件数据
|
||||
|
||||
参数:
|
||||
limit_type: 限制类型
|
||||
|
||||
返回:
|
||||
dict: 文件数据
|
||||
"""
|
||||
if limit_type == PluginLimitType.CD:
|
||||
return self.cd_data
|
||||
elif limit_type == PluginLimitType.COUNT:
|
||||
return self.count_data
|
||||
else:
|
||||
return self.block_data
|
||||
|
||||
def __set_db_limits(
|
||||
self,
|
||||
db_limits: list[PluginLimit],
|
||||
module2plugin: dict[str, PluginInfo],
|
||||
limit_type: PluginLimitType,
|
||||
) -> tuple[list[PluginLimit], list[PluginLimit], list[int]]:
|
||||
"""更新cd限制数据
|
||||
|
||||
参数:
|
||||
db_limits: 数据库limits
|
||||
module2plugin: 模块:插件信息
|
||||
|
||||
返回:
|
||||
tuple[list[PluginLimit], list[PluginLimit]]: 创建列表,更新列表
|
||||
"""
|
||||
update_list = []
|
||||
create_list = []
|
||||
delete_list = []
|
||||
db_type_limits = [
|
||||
limit for limit in db_limits if limit.limit_type == limit_type
|
||||
]
|
||||
if data := self.__get_file_data(limit_type):
|
||||
db_type_limit_modules = [
|
||||
(limit.module_path, limit.id) for limit in db_type_limits
|
||||
]
|
||||
delete_list.extend(
|
||||
id
|
||||
for module_path, id in db_type_limit_modules
|
||||
if module_path not in data.keys()
|
||||
)
|
||||
for k, v in data.items():
|
||||
if not module2plugin.get(k):
|
||||
if k != "test":
|
||||
logger.warning(
|
||||
f"插件模块 {k} 未加载,已过滤当前 {v._type} 限制..."
|
||||
)
|
||||
continue
|
||||
db_data = [limit for limit in db_type_limits if limit.module_path == k]
|
||||
db_data, is_create = self.__set_data(
|
||||
k, db_data[0] if db_data else None, v, limit_type, module2plugin
|
||||
)
|
||||
if is_create:
|
||||
create_list.append(db_data)
|
||||
else:
|
||||
update_list.append(db_data)
|
||||
else:
|
||||
delete_list = [limit.id for limit in db_type_limits]
|
||||
return create_list, update_list, delete_list
|
||||
|
||||
async def __set_all_limit(
|
||||
self,
|
||||
) -> tuple[list[PluginLimit], list[PluginLimit], list[int]]:
|
||||
"""获取所有插件限制数据
|
||||
|
||||
返回:
|
||||
tuple[list[PluginLimit], list[PluginLimit]]: 创建列表,更新列表
|
||||
"""
|
||||
db_limits = await PluginLimit.all()
|
||||
modules = set(
|
||||
list(self.cd_data.keys())
|
||||
+ list(self.block_data.keys())
|
||||
+ list(self.count_data.keys())
|
||||
)
|
||||
plugins = await PluginInfo.get_plugins(module_path__in=modules)
|
||||
module2plugin = {p.module_path: p for p in plugins}
|
||||
create_list, update_list, delete_list = self.__set_db_limits(
|
||||
db_limits, module2plugin, PluginLimitType.CD
|
||||
)
|
||||
create_list1, update_list1, delete_list1 = self.__set_db_limits(
|
||||
db_limits, module2plugin, PluginLimitType.COUNT
|
||||
)
|
||||
create_list2, update_list2, delete_list2 = self.__set_db_limits(
|
||||
db_limits, module2plugin, PluginLimitType.BLOCK
|
||||
)
|
||||
all_create = create_list + create_list1 + create_list2
|
||||
all_update = update_list + update_list1 + update_list2
|
||||
all_delete = delete_list + delete_list1 + delete_list2
|
||||
return all_create, all_update, all_delete
|
||||
|
||||
async def load_to_db(self):
|
||||
"""读取配置文件"""
|
||||
|
||||
create_list, update_list, delete_list = await self.__set_all_limit()
|
||||
if create_list:
|
||||
await PluginLimit.bulk_create(create_list)
|
||||
if update_list:
|
||||
for limit in update_list:
|
||||
await limit.save(
|
||||
update_fields=[
|
||||
"status",
|
||||
"check_type",
|
||||
"watch_type",
|
||||
"result",
|
||||
"cd",
|
||||
"max_count",
|
||||
]
|
||||
)
|
||||
# TODO: tortoise.exceptions.OperationalError:syntax error at or near "GROUP"
|
||||
# await PluginLimit.bulk_update(
|
||||
# update_list,
|
||||
# ["status", "check_type", "watch_type", "result", "cd", "max_count"],
|
||||
# )
|
||||
if delete_list:
|
||||
await PluginLimit.filter(id__in=delete_list).delete()
|
||||
cnt = await PluginLimit.filter(status=True).count()
|
||||
logger.info(f"已经加载 {cnt} 个插件限制.")
|
||||
|
||||
|
||||
manager = Manager()
|
||||
Reference in New Issue
Block a user