优化manager代码

This commit is contained in:
HibiKier 2022-11-21 20:43:41 +08:00
parent 49e38862af
commit cd66b7f5b8
41 changed files with 1974 additions and 1760 deletions

View File

@ -296,6 +296,10 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
## 更新 ## 更新
### 2022/11/21
* 优化manager, hook代码
### 2022/11/19 ### 2022/11/19
* 修改优化帮助图片生成逻辑 * 修改优化帮助图片生成逻辑

View File

@ -23,7 +23,7 @@ except ModuleNotFoundError:
import json import json
async def group_current_status(group_id: int) -> str: def group_current_status(group_id: int) -> str:
""" """
获取当前所有通知的开关 获取当前所有通知的开关
:param group_id: 群号 :param group_id: 群号
@ -31,17 +31,17 @@ async def group_current_status(group_id: int) -> str:
rst = "[被动技能 状态]\n" rst = "[被动技能 状态]\n"
_data = group_manager.get_task_data() _data = group_manager.get_task_data()
for task in _data.keys(): for task in _data.keys():
rst += f'{_data[task]}: {"" if await group_manager.check_group_task_status(group_id, task) else "×"}\n' rst += f'{_data[task]}: {"" if group_manager.check_group_task_status(group_id, task) else "×"}\n'
return rst.strip() return rst.strip()
custom_welcome_msg_json = ( custom_welcome_msg_json = (
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json" Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
) )
async def custom_group_welcome( async def custom_group_welcome(
msg: str, imgs: List[str], user_id: int, group_id: int msg: str, imgs: List[str], user_id: int, group_id: int
) -> str: ) -> str:
""" """
替换群欢迎消息 替换群欢迎消息
@ -104,20 +104,21 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
if cmd == "全部被动": if cmd == "全部被动":
for task in task_data: for task in task_data:
if status == "开启": if status == "开启":
if not await group_manager.check_group_task_status(group_id, task): if not group_manager.check_group_task_status(group_id, task):
await group_manager.open_group_task(group_id, task) group_manager.open_group_task(group_id, task)
else: else:
if await group_manager.check_group_task_status(group_id, task): if group_manager.check_group_task_status(group_id, task):
await group_manager.close_group_task(group_id, task) group_manager.close_group_task(group_id, task)
if group_help_file.exists(): if group_help_file.exists():
group_help_file.unlink() group_help_file.unlink()
return f"{status} 全部被动技能!" return f"{status} 全部被动技能!"
if cmd == "全部功能": if cmd == "全部功能":
for f in plugins2settings_manager.get_data(): for f in plugins2settings_manager.get_data():
if status == "开启": if status == "开启":
group_manager.unblock_plugin(f, group_id) group_manager.unblock_plugin(f, group_id, False)
else: else:
group_manager.block_plugin(f, group_id) group_manager.block_plugin(f, group_id, False)
group_manager.save()
if group_help_file.exists(): if group_help_file.exists():
group_help_file.unlink() group_help_file.unlink()
return f"{status} 全部功能!" return f"{status} 全部功能!"
@ -129,18 +130,18 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
module = f"{module}:super" module = f"{module}:super"
if status == "开启": if status == "开启":
if type_ == "task": if type_ == "task":
if await group_manager.check_group_task_status(group_id, module): if group_manager.check_group_task_status(group_id, module):
return f"被动 {task_data[module]} 正处于开启状态!不要重复开启." return f"被动 {task_data[module]} 正处于开启状态!不要重复开启."
await group_manager.open_group_task(group_id, module) group_manager.open_group_task(group_id, module)
else: else:
if group_manager.get_plugin_status(module, group_id): if group_manager.get_plugin_status(module, group_id):
return f"功能 {cmd} 正处于开启状态!不要重复开启." return f"功能 {cmd} 正处于开启状态!不要重复开启."
group_manager.unblock_plugin(module, group_id) group_manager.unblock_plugin(module, group_id)
else: else:
if type_ == "task": if type_ == "task":
if not await group_manager.check_group_task_status(group_id, module): if not group_manager.check_group_task_status(group_id, module):
return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭." return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭."
await group_manager.close_group_task(group_id, module) group_manager.close_group_task(group_id, module)
else: else:
if not group_manager.get_plugin_status(module, group_id): if not group_manager.get_plugin_status(module, group_id):
return f"功能 {cmd} 正处于关闭状态!不要重复关闭." return f"功能 {cmd} 正处于关闭状态!不要重复关闭."
@ -197,17 +198,17 @@ def _get_plugin_status() -> MessageSegment:
flag = plugins_manager.get_plugin_block_type(module) flag = plugins_manager.get_plugin_block_type(module)
flag = flag.upper() + " CLOSE" if flag else "OPEN" flag = flag.upper() + " CLOSE" if flag else "OPEN"
try: try:
plugin_name = plugins_manager.get(module)["plugin_name"] plugin_name = plugins_manager.get(module).plugin_name
if ( if (
"[Hidden]" in plugin_name "[Hidden]" in plugin_name
or "[Admin]" in plugin_name or "[Admin]" in plugin_name
or "[Superuser]" in plugin_name or "[Superuser]" in plugin_name
): ):
continue continue
rst += f"{plugin_name}" rst += f"{plugin_name}"
except KeyError: except KeyError:
rst += f"{module}" rst += f"{module}"
if plugins_manager.get(module)["error"]: if plugins_manager.get(module).error:
rst += "[ERROR]" rst += "[ERROR]"
rst += "\n" rst += "\n"
flag_str += f"{flag}\n" flag_str += f"{flag}\n"
@ -238,12 +239,12 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
async with db.transaction(): async with db.transaction():
# 更新权限 # 更新权限
if ( if (
user_info["role"] user_info["role"]
in [ in [
"owner", "owner",
"admin", "admin",
] ]
and not await LevelUser.is_group_flag(user_info["user_id"], group_id) and not await LevelUser.is_group_flag(user_info["user_id"], group_id)
): ):
await LevelUser.set_level( await LevelUser.set_level(
user_info["user_id"], user_info["user_id"],
@ -272,10 +273,10 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
"%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M:%S",
) )
if await GroupInfoUser.add_member_info( if await GroupInfoUser.add_member_info(
user_info["user_id"], user_info["user_id"],
user_info["group_id"], user_info["group_id"],
nickname, nickname,
join_time, join_time,
): ):
_exist_member_list.append(int(user_info["user_id"])) _exist_member_list.append(int(user_info["user_id"]))
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功") logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
@ -317,7 +318,4 @@ def set_group_bot_status(group_id: int, status: bool) -> str:
return "呜..醒来了..." return "呜..醒来了..."
else: else:
group_manager.shutdown_group_bot_status(group_id) group_manager.shutdown_group_bot_status(group_id)
# for x in group_manager.get_task_data():
# group_manager.close_group_task(group_id, x)
return "那我先睡觉了..." return "那我先睡觉了..."

View File

@ -2,18 +2,23 @@ from nonebot.adapters.onebot.v11 import Event
from utils.manager import group_manager, plugins2settings_manager from utils.manager import group_manager, plugins2settings_manager
from utils.utils import get_message_text from utils.utils import get_message_text
from services.log import logger from services.log import logger
import time
cmd = [] cmd = []
v = time.time()
def switch_rule(event: Event) -> bool: def switch_rule(event: Event) -> bool:
""" """
检测文本是否是关闭功能命令 说明:
:param event: pass 检测文本是否是关闭功能命令
参数:
:param event: pass
""" """
global cmd global cmd
try: try:
if not cmd: if not cmd or time.time() - v > 60 * 60:
cmd = ["关闭全部被动", "开启全部被动", "开启全部功能", "关闭全部功能"] cmd = ["关闭全部被动", "开启全部被动", "开启全部功能", "关闭全部功能"]
_data = group_manager.get_task_data() _data = group_manager.get_task_data()
for key in _data: for key in _data:
@ -22,10 +27,10 @@ def switch_rule(event: Event) -> bool:
cmd.append(f"开启 {_data[key]}") cmd.append(f"开启 {_data[key]}")
cmd.append(f"关闭 {_data[key]}") cmd.append(f"关闭 {_data[key]}")
_data = plugins2settings_manager.get_data() _data = plugins2settings_manager.get_data()
for key in _data: for key in _data.keys():
try: try:
if isinstance(_data[key]["cmd"], list): if isinstance(_data[key].cmd, list):
for x in _data[key]["cmd"]: for x in _data[key].cmd:
cmd.append(f"开启{x}") cmd.append(f"开启{x}")
cmd.append(f"关闭{x}") cmd.append(f"关闭{x}")
cmd.append(f"开启 {x}") cmd.append(f"开启 {x}")

View File

@ -110,7 +110,7 @@ async def _():
@group_task_status.handle() @group_task_status.handle()
async def _(event: GroupMessageEvent): async def _(event: GroupMessageEvent):
await group_task_status.send(await group_current_status(event.group_id)) await group_task_status.send(group_current_status(event.group_id))
@group_status.handle() @group_status.handle()

View File

@ -16,9 +16,9 @@ admin_help_image = IMAGE_PATH / 'admin_help_img.png'
@driver.on_bot_connect @driver.on_bot_connect
async def init_task(bot: Bot = None): async def init_task():
if not group_manager.get_task_data(): if not group_manager.get_task_data():
await group_manager.init_group_task() group_manager.load_task()
logger.info(f'已成功加载 {len(group_manager.get_task_data())} 个被动技能.') logger.info(f'已成功加载 {len(group_manager.get_task_data())} 个被动技能.')

View File

@ -44,7 +44,7 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
gl = [ gl = [
g["group_id"] g["group_id"]
for g in gl for g in gl
if await group_manager.check_group_task_status(g["group_id"], "broadcast") if group_manager.check_group_task_status(g["group_id"], "broadcast")
] ]
g_cnt = len(gl) g_cnt = len(gl)
cnt = 0 cnt = 0

View File

@ -40,16 +40,14 @@ async def _create_help_img(
:param help_image: 图片路径 :param help_image: 图片路径
:param simple_help_image: 简易帮助图片路径 :param simple_help_image: 简易帮助图片路径
""" """
_matchers = get_matchers(True)
width = 0 width = 0
matchers_data = {} matchers_data = {}
_des_tmp = {} _des_tmp = {}
_plugin_name_tmp = []
_tmp = [] _tmp = []
tmp_img = BuildImage(0, 0, plain_text="1", font_size=24) tmp_img = BuildImage(0, 0, plain_text="1", font_size=24)
font_height = tmp_img.h font_height = tmp_img.h
# 插件分类 # 插件分类
for matcher in _matchers: for matcher in get_matchers(True):
plugin_name = None plugin_name = None
_plugin = matcher.plugin _plugin = matcher.plugin
if not _plugin: if not _plugin:
@ -67,7 +65,6 @@ async def _create_help_img(
"[hidden]" in plugin_name.lower() "[hidden]" in plugin_name.lower()
or "[admin]" in plugin_name.lower() or "[admin]" in plugin_name.lower()
or "[superuser]" in plugin_name.lower() or "[superuser]" in plugin_name.lower()
or plugin_name in _plugin_name_tmp
or plugin_name == "帮助" or plugin_name == "帮助"
): ):
continue continue
@ -75,11 +72,9 @@ async def _create_help_img(
text_type = 0 text_type = 0
if plugins2settings_manager.get( if plugins2settings_manager.get(
matcher.plugin_name matcher.plugin_name
) and plugins2settings_manager[matcher.plugin_name].get("plugin_type"): ) and plugins2settings_manager.get(matcher.plugin_name).plugin_type:
plugin_type = tuple( plugin_type = tuple(
plugins2settings_manager.get_plugin_data(matcher.plugin_name)[ plugins2settings_manager.get_plugin_data(matcher.plugin_name).plugin_type
"plugin_type"
]
) )
else: else:
try: try:
@ -128,10 +123,7 @@ async def _create_help_img(
if plugin_des not in _des_tmp: if plugin_des not in _des_tmp:
_des_tmp[plugin_des] = plugin_name _des_tmp[plugin_des] = plugin_name
except AttributeError as e: except AttributeError as e:
if plugin_name not in _plugin_name_tmp: logger.warning(f"获取功能 {matcher.plugin_name}: {plugin_name} 设置失败...e{e}")
logger.warning(f"获取功能 {matcher.plugin_name}: {plugin_name} 设置失败...e{e}")
if plugin_name not in _plugin_name_tmp:
_plugin_name_tmp.append(plugin_name)
help_img_list = [] help_img_list = []
simple_help_img_list = [] simple_help_img_list = []
types = list(matchers_data.keys()) types = list(matchers_data.keys())
@ -284,45 +276,13 @@ async def _create_help_img(
B.save(simple_help_image) B.save(simple_help_image)
def get_max_width_or_paste(
simple_help_img_list: List[BuildImage], B: BuildImage = None, is_paste: bool = False
) -> Tuple[int, BuildImage]:
"""
获取最大宽度或直接贴图
:param simple_help_img_list: 简单帮助图片列表
:param B: 背景图
:param is_paste: 是否直接贴图
"""
current_width = 50
current_height = 180
max_width = simple_help_img_list[0].w
for i in range(len(simple_help_img_list)):
try:
if is_paste and B:
B.paste(simple_help_img_list[i], (current_width, current_height), True)
current_height += simple_help_img_list[i].h + 40
if current_height + simple_help_img_list[i + 1].h > B.h - 10:
current_height = 180
current_width += max_width + 30
max_width = 0
elif simple_help_img_list[i].w > max_width:
max_width = simple_help_img_list[i].w
except IndexError:
pass
if current_width > simple_help_img_list[0].w + 50:
current_width += simple_help_img_list[-1].w
return current_width, B
def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]: def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]:
""" """
获取功能的帮助信息 获取功能的帮助信息
:param msg: 功能cmd :param msg: 功能cmd
:param is_super: 是否为超级用户 :param is_super: 是否为超级用户
""" """
module = plugins2settings_manager.get_plugin_module(msg) module = plugins2settings_manager.get_plugin_module(msg) or admin_manager.get_plugin_module(msg)
if not module:
module = admin_manager.get_plugin_module(msg)
if module: if module:
try: try:
plugin = nonebot.plugin.get_plugin(module) plugin = nonebot.plugin.get_plugin(module)

View File

@ -1,5 +1,37 @@
from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent from typing import Optional
from utils.manager import plugins2block_manager, StaticData
import nonebot
from nonebot.adapters.onebot.v11 import (
GroupMessageEvent,
PrivateMessageEvent,
Bot,
Event,
MessageEvent,
Message,
PokeNotifyEvent,
)
from nonebot.exception import ActionFailed, IgnoredException
from nonebot.internal.matcher import Matcher
from models.bag_user import BagUser
from models.ban_user import BanUser
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from models.level_user import LevelUser
from models.user_shop_gold_log import UserShopGoldLog
from utils.manager import (
plugins2block_manager,
StaticData,
plugins2settings_manager,
group_manager,
admin_manager,
plugins_manager,
plugins2cd_manager,
plugins2count_manager,
)
from utils.message_builder import at
from utils.utils import FreqLimiter
from configs.config import Config
import time import time
ignore_rst_module = ["ai", "poke", "dialogue"] ignore_rst_module = ["ai", "poke", "dialogue"]
@ -8,7 +40,6 @@ other_limit_plugins = ["poke"]
class StatusMessageManager(StaticData): class StatusMessageManager(StaticData):
def __init__(self): def __init__(self):
super().__init__(None) super().__init__(None)
@ -39,8 +70,8 @@ def set_block_limit_false(event, module):
""" """
if plugins2block_manager.check_plugin_block_status(module): if plugins2block_manager.check_plugin_block_status(module):
plugin_block_data = plugins2block_manager.get_plugin_block_data(module) plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
check_type = plugin_block_data["check_type"] check_type = plugin_block_data.check_type
limit_type = plugin_block_data["limit_type"] limit_type = plugin_block_data.limit_type
if not ( if not (
(isinstance(event, GroupMessageEvent) and check_type == "private") (isinstance(event, GroupMessageEvent) and check_type == "private")
or (isinstance(event, PrivateMessageEvent) and check_type == "group") or (isinstance(event, PrivateMessageEvent) and check_type == "group")
@ -50,3 +81,436 @@ def set_block_limit_false(event, module):
block_type_ = event.group_id block_type_ = event.group_id
plugins2block_manager.set_false(block_type_, module) plugins2block_manager.set_false(block_type_, module)
async def send_msg(msg: str, bot: Bot, event: MessageEvent):
"""
说明:
发送信息
参数:
:param msg: pass
:param bot: pass
:param event: pass
"""
if "[uname]" in msg:
uname = event.sender.card or event.sender.nickname
msg = msg.replace("[uname]", uname)
if "[nickname]" in msg:
if isinstance(event, GroupMessageEvent):
nickname = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
else:
nickname = await FriendUser.get_friend_nickname(event.user_id)
msg = msg.replace("[nickname]", nickname)
if "[at]" in msg and isinstance(event, GroupMessageEvent):
msg = msg.replace("[at]", str(at(event.user_id)))
try:
if isinstance(event, GroupMessageEvent):
status_message_manager.add(event.group_id)
await bot.send_group_msg(group_id=event.group_id, message=Message(msg))
else:
status_message_manager.add(event.user_id)
await bot.send_private_msg(user_id=event.user_id, message=Message(msg))
except ActionFailed:
pass
class ReturnException(Exception):
pass
class AuthChecker:
"""
权限检查
"""
checker: Optional["AuthChecker"] = None
def __init__(self):
self._flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
self._flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
self._flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
self._flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
def __new__(cls, *args, **kwargs):
if not cls.checker:
cls.checker = super().__new__(cls)
return cls.checker
async def auth(self, matcher: Matcher, bot: Bot, event: Event):
"""
说明:
权限检查
参数:
:param matcher: matcher
:param bot: bot
:param event: event
"""
try:
plugin_name = matcher.plugin_name
cost_gold = await self.auth_cost(plugin_name, bot, event)
await self.auth_basic(plugin_name, bot, event)
self.auth_group(plugin_name, bot, event)
await self.auth_admin(plugin_name, matcher, bot, event)
await self.auth_plugin(plugin_name, matcher, bot, event)
await self.auth_limit(plugin_name, bot, event)
if cost_gold and str(event.user_id) not in bot.config.superusers:
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
except ReturnException:
return
async def auth_limit(self, plugin_name: str, bot: Bot, event: Event):
"""
说明:
插件限制
参数:
:param plugin_name: 模块名
:param bot: bot
:param event: event
"""
if plugins2cd_manager.check_plugin_cd_status(plugin_name):
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(plugin_name)
check_type = plugin_cd_data.check_type
limit_type = plugin_cd_data.limit_type
msg = plugin_cd_data.rst
if (
(isinstance(event, PrivateMessageEvent) and check_type == "private")
or (isinstance(event, GroupMessageEvent) and check_type == "group")
or plugins2cd_manager.get_plugin_data(plugin_name).check_type == "all"
):
cd_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
cd_type_ = event.group_id
if not plugins2cd_manager.check(plugin_name, cd_type_):
if msg:
await send_msg(msg, bot, event)
raise IgnoredException(f"{plugin_name} 正在cd中...")
else:
plugins2cd_manager.start_cd(plugin_name, cd_type_)
# Block
if plugins2block_manager.check_plugin_block_status(plugin_name):
plugin_block_data = plugins2block_manager.get_plugin_block_data(plugin_name)
check_type = plugin_block_data.check_type
limit_type = plugin_block_data.limit_type
msg = plugin_block_data.rst
if (
(isinstance(event, PrivateMessageEvent) and check_type == "private")
or (isinstance(event, GroupMessageEvent) and check_type == "group")
or check_type == "all"
):
block_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
block_type_ = event.group_id
if plugins2block_manager.check(block_type_, plugin_name):
if msg:
await send_msg(msg, bot, event)
raise IgnoredException(f"{event.user_id}正在调用{plugin_name}....")
else:
plugins2block_manager.set_true(block_type_, plugin_name)
# Count
if (
plugins2count_manager.check_plugin_count_status(plugin_name)
and event.user_id not in bot.config.superusers
):
plugin_count_data = plugins2count_manager.get_plugin_count_data(plugin_name)
limit_type = plugin_count_data.limit_type
msg = plugin_count_data.rst
count_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
count_type_ = event.group_id
if not plugins2count_manager.check(plugin_name, count_type_):
if msg:
await send_msg(msg, bot, event)
raise IgnoredException(f"{plugin_name} count次数限制...")
else:
plugins2count_manager.increase(plugin_name, count_type_)
async def auth_plugin(self, plugin_name: str, matcher: Matcher, bot: Bot, event: Event):
"""
说明:
插件状态
参数:
:param plugin_name: 模块名
:param matcher: matcher
:param bot: bot
:param event: event
"""
if plugin_name in plugins2settings_manager.keys() and matcher.priority not in [
1,
999,
]:
# 戳一戳单独判断
if (
isinstance(event, GroupMessageEvent)
or isinstance(event, PokeNotifyEvent)
or matcher.plugin_name in other_limit_plugins
):
if status_message_manager.get(event.group_id) is None:
status_message_manager.delete(event.group_id)
if plugins2settings_manager[
plugin_name
].level > group_manager.get_group_level(event.group_id):
try:
if (
self._flmt_g.check(event.user_id)
and plugin_name not in ignore_rst_module
):
self._flmt_g.start_cd(event.user_id)
await bot.send_group_msg(
group_id=event.group_id, message="群权限不足..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("群权限不足")
# 插件状态
if not group_manager.get_plugin_status(plugin_name, event.group_id):
try:
if plugin_name not in ignore_rst_module and self._flmt_s.check(
event.group_id
):
self._flmt_s.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该群未开启此功能.."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("未开启此功能...")
# 管理员禁用
if not group_manager.get_plugin_status(
f"{plugin_name}:super", event.group_id
):
try:
if (
self._flmt_s.check(event.group_id)
and plugin_name not in ignore_rst_module
):
self._flmt_s.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="管理员禁用了此群该功能..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("管理员禁用了此群该功能...")
# 群聊禁用
if not plugins_manager.get_plugin_status(
plugin_name, block_type="group"
):
try:
if (
self._flmt_c.check(event.group_id)
and plugin_name not in ignore_rst_module
):
self._flmt_c.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该功能在群聊中已被禁用..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("该插件在群聊中已被禁用...")
else:
# 私聊禁用
if not plugins_manager.get_plugin_status(
plugin_name, block_type="private"
):
try:
if self._flmt_c.check(event.user_id):
self._flmt_c.start_cd(event.user_id)
await bot.send_private_msg(
user_id=event.user_id, message="该功能在私聊中已被禁用..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.user_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("该插件在私聊中已被禁用...")
# 维护
if not plugins_manager.get_plugin_status(plugin_name, block_type="all"):
if isinstance(
event, GroupMessageEvent
) and group_manager.check_group_is_white(event.group_id):
raise ReturnException()
try:
if isinstance(event, GroupMessageEvent):
if (
self._flmt_c.check(event.group_id)
and plugin_name not in ignore_rst_module
):
self._flmt_c.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="此功能正在维护..."
)
else:
await bot.send_private_msg(
user_id=event.user_id, message="此功能正在维护..."
)
except ActionFailed:
pass
if event.is_tome():
id_ = (
event.group_id
if isinstance(event, GroupMessageEvent)
else event.user_id
)
status_message_manager.add(id_)
set_block_limit_false(event, plugin_name)
raise IgnoredException("此功能正在维护...")
async def auth_admin(self, plugin_name: str, matcher: Matcher, bot: Bot, event: Event):
"""
说明:
管理员命令 个人权限
参数:
:param plugin_name: 模块名
:param matcher: matcher
:param bot: bot
:param event: event
"""
if plugin_name in admin_manager.keys() and matcher.priority not in [1, 999]:
if isinstance(event, GroupMessageEvent):
# 个人权限
if (
not await LevelUser.check_level(
event.user_id,
event.group_id,
admin_manager.get_plugin_level(plugin_name),
)
and admin_manager.get_plugin_level(plugin_name) > 0
):
try:
if self._flmt.check(event.user_id):
self._flmt.start_cd(event.user_id)
await bot.send_group_msg(
group_id=event.group_id,
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
f"{admin_manager.get_plugin_level(plugin_name)}",
)
except ActionFailed:
pass
set_block_limit_false(event, plugin_name)
if event.is_tome():
status_message_manager.add(event.group_id)
raise IgnoredException("权限不足")
else:
if not await LevelUser.check_level(
event.user_id, 0, admin_manager.get_plugin_level(plugin_name)
):
try:
await bot.send_private_msg(
user_id=event.user_id,
message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(plugin_name)}",
)
except ActionFailed:
pass
set_block_limit_false(event, plugin_name)
if event.is_tome():
status_message_manager.add(event.user_id)
raise IgnoredException("权限不足")
def auth_group(self, plugin_name: str, bot: Bot, event: Event):
"""
说明:
群黑名单检测 群总开关检测
参数:
:param plugin_name: 模块名
:param bot: bot
:param event: event
"""
if isinstance(event, GroupMessageEvent) or plugin_name in other_limit_plugins:
try:
if (
group_manager.get_group_level(event.group_id) < 0
and str(event.user_id) not in bot.config.superusers
):
raise IgnoredException("群黑名单")
if not group_manager.check_group_bot_status(event.group_id):
try:
if str(event.get_message()) != "醒来":
raise IgnoredException("功能总开关关闭状态")
except ValueError:
raise IgnoredException("功能总开关关闭状态")
except AttributeError:
pass
async def auth_basic(self, plugin_name: str, bot: Bot, event: Event):
"""
说明:
检测是否满足超级用户权限是否被ban等
参数:
:param plugin_name: 模块名
:param bot: bot
:param event: event
"""
ban = await BanUser.is_ban(event.user_id)
try:
if (
(
not isinstance(event, MessageEvent)
and plugin_name not in other_limit_plugins
)
or await BanUser.is_ban(event.user_id)
and str(event.user_id) not in bot.config.superusers
) or (
str(event.user_id) in bot.config.superusers
and plugins2settings_manager.get_plugin_data(plugin_name)
and not plugins2settings_manager.get_plugin_data(
plugin_name
).limit_superuser
):
raise ReturnException()
_plugin = nonebot.plugin.get_plugin(plugin_name)
_module = _plugin.module
_plugin_name = _module.__getattribute__("__zx_plugin_name__")
if (
"[superuser]" in _plugin_name.lower()
and str(event.user_id) in bot.config.superusers
):
raise ReturnException()
except AttributeError:
pass
async def auth_cost(self, plugin_name: str, bot: Bot, event: Event) -> int:
"""
说明:
检测是否满足金币条件
参数:
:param plugin_name: 模块名
:param bot: bot
:param event: event
"""
cost_gold = 0
if isinstance(event, GroupMessageEvent) and (
psm := plugins2settings_manager.get_plugin_data(plugin_name)
):
if psm.cost_gold > 0:
if (
await BagUser.get_gold(event.user_id, event.group_id)
< psm.cost_gold
):
await send_msg(f"金币不足..该功能需要{psm.cost_gold}金币..", bot, event)
raise IgnoredException(f"{plugin_name} 金币限制...")
# 当插件不阻塞超级用户时,超级用户提前扣除金币
if (
str(event.user_id) in bot.config.superusers
and not psm.limit_superuser
):
await BagUser.spend_gold(
event.user_id, event.group_id, psm.cost_gold
)
await UserShopGoldLog.add_shop_log(
event.user_id, event.group_id, 2, plugin_name, psm.cost_gold, 1
)
cost_gold = psm.cost_gold
return cost_gold

View File

@ -1,395 +1,36 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from models.bag_user import BagUser
from models.user_shop_gold_log import UserShopGoldLog
from utils.manager import (
plugins2settings_manager,
admin_manager,
group_manager,
plugins_manager,
plugins2cd_manager,
plugins2block_manager,
plugins2count_manager,
)
from ._utils import (
set_block_limit_false,
status_message_manager,
ignore_rst_module,
other_limit_plugins,
)
from nonebot.typing import T_State
from typing import Optional from typing import Optional
from nonebot.adapters.onebot.v11 import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
ActionFailed,
MessageEvent, MessageEvent,
GroupMessageEvent,
PokeNotifyEvent,
PrivateMessageEvent,
Message,
Event, Event,
) )
from configs.config import Config from nonebot.matcher import Matcher
from models.ban_user import BanUser from nonebot.message import run_preprocessor, run_postprocessor
from utils.utils import FreqLimiter from nonebot.typing import T_State
from utils.message_builder import at
from models.level_user import LevelUser
import nonebot
_flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD")) from ._utils import (
_flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD")) set_block_limit_false,
_flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD")) AuthChecker,
_flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD")) )
# 权限检测 # # 权限检测
@run_preprocessor @run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State): async def _(matcher: Matcher, bot: Bot, event: Event):
module = matcher.plugin_name await AuthChecker().auth(matcher, bot, event)
plugins2info_dict = plugins2settings_manager.get_data()
# 功能的金币检测 #######################################
# 功能的金币检测 #######################################
# 功能的金币检测 #######################################
cost_gold = 0
if isinstance(
event, GroupMessageEvent
) and plugins2settings_manager.get_plugin_data(module).get("cost_gold"):
cost_gold = plugins2settings_manager.get_plugin_data(module).get("cost_gold")
if await BagUser.get_gold(event.user_id, event.group_id) < cost_gold:
await send_msg(f"金币不足..该功能需要{cost_gold}金币..", bot, event)
raise IgnoredException(f"{module} 金币限制...")
await UserShopGoldLog.add_shop_log(event.user_id, event.group_id, 2, matcher.plugin_name, cost_gold, 1)
# 当插件不阻塞超级用户时,超级用户提前扣除金币
if (
str(event.user_id) in bot.config.superusers
and not plugins2info_dict[module]["limit_superuser"]
):
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
try:
if (
(not isinstance(event, MessageEvent) and module not in other_limit_plugins)
or await BanUser.is_ban(event.user_id)
and str(event.user_id) not in bot.config.superusers
) or (
str(event.user_id) in bot.config.superusers
and plugins2info_dict.get(module)
and not plugins2info_dict[module]["limit_superuser"]
):
return
except AttributeError:
pass
# 超级用户命令
try:
_plugin = nonebot.plugin.get_plugin(module)
_module = _plugin.module
plugin_name = _module.__getattribute__("__zx_plugin_name__")
if (
"[superuser]" in plugin_name.lower()
and str(event.user_id) in bot.config.superusers
):
return
except AttributeError:
pass
# 群黑名单检测 群总开关检测
if (
isinstance(event, GroupMessageEvent)
or matcher.plugin_name in other_limit_plugins
):
try:
if (
group_manager.get_group_level(event.group_id) < 0
and str(event.user_id) not in bot.config.superusers
):
raise IgnoredException("群黑名单")
if not group_manager.check_group_bot_status(event.group_id):
try:
if str(event.get_message()) != "醒来":
raise IgnoredException("功能总开关关闭状态")
except ValueError:
raise IgnoredException("功能总开关关闭状态")
except AttributeError:
pass
if module in admin_manager.keys() and matcher.priority not in [1, 999]:
if isinstance(event, GroupMessageEvent):
# 个人权限
if (
not await LevelUser.check_level(
event.user_id,
event.group_id,
admin_manager.get_plugin_level(module),
)
and admin_manager.get_plugin_level(module) > 0
):
try:
if _flmt.check(event.user_id):
_flmt.start_cd(event.user_id)
await bot.send_group_msg(
group_id=event.group_id,
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
f"{admin_manager.get_plugin_level(module)}",
)
except ActionFailed:
pass
set_block_limit_false(event, module)
if event.is_tome():
status_message_manager.add(event.group_id)
raise IgnoredException("权限不足")
else:
if not await LevelUser.check_level(
event.user_id, 0, admin_manager.get_plugin_level(module)
):
try:
await bot.send_private_msg(
user_id=event.user_id,
message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(module)}",
)
except ActionFailed:
pass
set_block_limit_false(event, module)
if event.is_tome():
status_message_manager.add(event.user_id)
raise IgnoredException("权限不足")
if module in plugins2info_dict.keys() and matcher.priority not in [1, 999]:
# 戳一戳单独判断
if (
isinstance(event, GroupMessageEvent)
or isinstance(event, PokeNotifyEvent)
or matcher.plugin_name in other_limit_plugins
):
if status_message_manager.get(event.group_id) is None:
status_message_manager.delete(event.group_id)
if plugins2info_dict[module]["level"] > group_manager.get_group_level(
event.group_id
):
try:
if _flmt_g.check(event.user_id) and module not in ignore_rst_module:
_flmt_g.start_cd(event.user_id)
await bot.send_group_msg(
group_id=event.group_id, message="群权限不足..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, module)
raise IgnoredException("群权限不足")
# 插件状态
if not group_manager.get_plugin_status(module, event.group_id):
try:
if module not in ignore_rst_module and _flmt_s.check(
event.group_id
):
_flmt_s.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该群未开启此功能.."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, module)
raise IgnoredException("未开启此功能...")
# 管理员禁用
if not group_manager.get_plugin_status(f"{module}:super", event.group_id):
try:
if (
_flmt_s.check(event.group_id)
and module not in ignore_rst_module
):
_flmt_s.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="管理员禁用了此群该功能..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, module)
raise IgnoredException("管理员禁用了此群该功能...")
# 群聊禁用
if not plugins_manager.get_plugin_status(module, block_type="group"):
try:
if (
_flmt_c.check(event.group_id)
and module not in ignore_rst_module
):
_flmt_c.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该功能在群聊中已被禁用..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, module)
raise IgnoredException("该插件在群聊中已被禁用...")
else:
# 私聊禁用
if not plugins_manager.get_plugin_status(module, block_type="private"):
try:
if _flmt_c.check(event.user_id):
_flmt_c.start_cd(event.user_id)
await bot.send_private_msg(
user_id=event.user_id, message="该功能在私聊中已被禁用..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.user_id)
set_block_limit_false(event, module)
raise IgnoredException("该插件在私聊中已被禁用...")
# 维护
if not plugins_manager.get_plugin_status(module, block_type="all"):
if isinstance(
event, GroupMessageEvent
) and group_manager.check_group_is_white(event.group_id):
return
try:
if isinstance(event, GroupMessageEvent):
if (
_flmt_c.check(event.group_id)
and module not in ignore_rst_module
):
_flmt_c.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="此功能正在维护..."
)
else:
await bot.send_private_msg(
user_id=event.user_id, message="此功能正在维护..."
)
except ActionFailed:
pass
if event.is_tome():
id_ = (
event.group_id
if isinstance(event, GroupMessageEvent)
else event.user_id
)
status_message_manager.add(id_)
set_block_limit_false(event, module)
raise IgnoredException("此功能正在维护...")
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# Cd
if plugins2cd_manager.check_plugin_cd_status(module):
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
check_type = plugin_cd_data["check_type"]
limit_type = plugin_cd_data["limit_type"]
rst = plugin_cd_data["rst"]
if (
(isinstance(event, PrivateMessageEvent) and check_type == "private")
or (isinstance(event, GroupMessageEvent) and check_type == "group")
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
):
cd_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
cd_type_ = event.group_id
if not plugins2cd_manager.check(module, cd_type_):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{module} 正在cd中...")
else:
plugins2cd_manager.start_cd(module, cd_type_)
# Block
if plugins2block_manager.check_plugin_block_status(module):
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
check_type = plugin_block_data["check_type"]
limit_type = plugin_block_data["limit_type"]
rst = plugin_block_data["rst"]
if (
(isinstance(event, PrivateMessageEvent) and check_type == "private")
or (isinstance(event, GroupMessageEvent) and check_type == "group")
or check_type == "all"
):
block_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
block_type_ = event.group_id
if plugins2block_manager.check(block_type_, module):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{event.user_id}正在调用{module}....")
else:
plugins2block_manager.set_true(block_type_, module)
# Count
if (
plugins2count_manager.check_plugin_count_status(module)
and event.user_id not in bot.config.superusers
):
plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
limit_type = plugin_count_data["limit_type"]
rst = plugin_count_data["rst"]
count_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
count_type_ = event.group_id
if not plugins2count_manager.check(module, count_type_):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{module} count次数限制...")
else:
plugins2count_manager.increase(module, count_type_)
# 功能花费的金币 #######################################
# 功能花费的金币 #######################################
if cost_gold:
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
async def send_msg(rst: str, bot: Bot, event: MessageEvent):
"""
发送信息
:param rst: pass
:param bot: pass
:param event: pass
"""
rst = await init_rst(rst, event)
try:
if isinstance(event, GroupMessageEvent):
status_message_manager.add(event.group_id)
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
else:
status_message_manager.add(event.user_id)
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
except ActionFailed:
pass
# 解除命令block阻塞 # 解除命令block阻塞
@run_postprocessor @run_postprocessor
async def _( async def _(
matcher: Matcher, matcher: Matcher,
exception: Optional[Exception], exception: Optional[Exception],
bot: Bot, bot: Bot,
event: Event, event: Event,
state: T_State, state: T_State,
): ):
if not isinstance(event, MessageEvent) and matcher.plugin_name != "poke": if not isinstance(event, MessageEvent) and matcher.plugin_name != "poke":
return return
module = matcher.plugin_name module = matcher.plugin_name
set_block_limit_false(event, module) set_block_limit_false(event, module)
async def init_rst(rst: str, event: MessageEvent):
if "[uname]" in rst:
uname = event.sender.card or event.sender.nickname
rst = rst.replace("[uname]", uname)
if "[nickname]" in rst:
if isinstance(event, GroupMessageEvent):
nickname = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
else:
nickname = await FriendUser.get_friend_nickname(event.user_id)
rst = rst.replace("[nickname]", nickname)
if "[at]" in rst and isinstance(event, GroupMessageEvent):
rst = rst.replace("[at]", str(at(event.user_id)))
return rst

View File

@ -39,7 +39,7 @@ async def _(bot: Bot, api: str, data: Dict[str, Any]):
group_id = data["group_id"] group_id = data["group_id"]
if group_manager.get_group_level( if group_manager.get_group_level(
group_id group_id
) < 0 or not await group_manager.check_group_task_status(group_id, task): ) < 0 or not group_manager.check_group_task_status(group_id, task):
raise MockApiException(f"被动技能 {task} 处于关闭状态...") raise MockApiException(f"被动技能 {task} 处于关闭状态...")
else: else:
msg = str(data["message"]).strip() msg = str(data["message"]).strip()

View File

@ -1,3 +1,4 @@
from configs.path_config import DATA_PATH
from .init_group_manager import init_group_manager, group_manager from .init_group_manager import init_group_manager, group_manager
from .init_plugins_config import init_plugins_config from .init_plugins_config import init_plugins_config
from .init_plugins_data import init_plugins_data, plugins_manager from .init_plugins_data import init_plugins_data, plugins_manager
@ -12,7 +13,6 @@ from .init_plugins_limit import (
from .init import init from .init import init
from .check_plugin_status import check_plugin_status from .check_plugin_status import check_plugin_status
from nonebot.adapters.onebot.v11 import Bot from nonebot.adapters.onebot.v11 import Bot
from configs.path_config import DATA_PATH
from services.log import logger from services.log import logger
from nonebot import Driver from nonebot import Driver
import nonebot import nonebot
@ -31,23 +31,21 @@ async def _():
""" """
初始化数据 初始化数据
""" """
_flag = False
config_file = DATA_PATH / "configs" / "plugins2config.yaml" config_file = DATA_PATH / "configs" / "plugins2config.yaml"
if not config_file.exists(): _flag = not config_file.exists()
_flag = True
init() init()
init_plugins_settings(DATA_PATH) init_plugins_settings()
init_plugins_cd_limit(DATA_PATH) init_plugins_cd_limit()
init_plugins_block_limit(DATA_PATH) init_plugins_block_limit()
init_plugins_count_limit(DATA_PATH) init_plugins_count_limit()
init_plugins_data(DATA_PATH) init_plugins_data()
init_plugins_config(DATA_PATH) init_plugins_config()
init_plugins_resources() init_plugins_resources()
init_none_plugin_count_manager() init_none_plugin_count_manager()
x = group_manager.get_super_old_data() # x = group_manager.get_super_old_data()
if x: # if x:
for key in x.keys(): # for key in x.keys():
plugins_manager.block_plugin(key, block_type=x[key]) # plugins_manager.block_plugin(key, block_type=x[key])
if _flag: if _flag:
raise Exception("首次运行已在configs目录下生成配置文件config.yaml修改后重启即可...") raise Exception("首次运行已在configs目录下生成配置文件config.yaml修改后重启即可...")
logger.info("初始化数据完成...") logger.info("初始化数据完成...")
@ -55,5 +53,5 @@ async def _():
@driver.on_bot_connect @driver.on_bot_connect
async def _(bot: Bot): async def _(bot: Bot):
await init_group_manager() # await init_group_manager()
await check_plugin_status(bot) await check_plugin_status(bot)

View File

@ -6,13 +6,13 @@ async def check_plugin_status(bot: Bot):
""" """
遍历查看插件加载情况 遍历查看插件加载情况
""" """
rst = "" msg = ""
for plugin in plugins_manager.keys(): for plugin in plugins_manager.keys():
data = plugins_manager.get(plugin) data = plugins_manager.get(plugin)
if data.get("error") or data.get("error") is None: if not data.error:
rst += f'{plugin}:{data["plugin_name"]}\n' msg += f'{plugin}:{data.plugin_name}\n'
if rst: if msg and bot.config.superusers:
rst = "以下插件加载失败..\n" + rst msg = "以下插件加载失败..\n" + msg
await bot.send_private_msg( await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]), message=rst[:-1] user_id=int(list(bot.config.superusers)[0]), message=msg.strip()
) )

View File

@ -19,36 +19,44 @@ def init_none_plugin_count_manager():
""" """
清除已删除插件数据 清除已删除插件数据
""" """
modules = [x.plugin_name for x in get_matchers()] modules = [x.plugin_name for x in get_matchers(True)]
plugins_manager_list = list(plugins_manager.keys()) plugins_manager_list = list(plugins_manager.keys())
for module in plugins_manager_list: for module in plugins_manager_list:
if module not in modules or none_plugin_count_manager.check(module): try:
try: if module not in modules or none_plugin_count_manager.check(module):
plugin_name = plugins_manager.get(module)["plugin_name"]
except (AttributeError, KeyError):
plugin_name = ""
if none_plugin_count_manager.check(module):
try: try:
plugins2settings_manager.delete(module) plugin_name = plugins_manager.get(module).plugin_name
plugins2settings_manager.save() except (AttributeError, KeyError):
plugins2count_manager.delete(module) plugin_name = ""
plugins2count_manager.save() if none_plugin_count_manager.check(module):
plugins2cd_manager.delete(module) try:
plugins2cd_manager.save() plugins2settings_manager.delete(module)
plugins2block_manager.delete(module) plugins2count_manager.delete(module)
plugins2block_manager.save() plugins2cd_manager.delete(module)
plugins_manager.delete(module) plugins2block_manager.delete(module)
plugins_manager.save() plugins_manager.delete(module)
# resources_manager.remove_resource(module) plugins_manager.save()
none_plugin_count_manager.delete(module) # resources_manager.remove_resource(module)
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...") none_plugin_count_manager.delete(module)
except Exception as e: logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...")
logger.exception( except Exception as e:
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}{e}") logger.exception(
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}{e}"
)
else:
none_plugin_count_manager.add_count(module)
logger.info(
f"{module}:{plugin_name} 插件疑似已删除,"
f"加载{none_plugin_count_manager._max_count}次失败后将清除对应插件数据,"
f"当前次数:{none_plugin_count_manager._data[module]}"
)
else: else:
none_plugin_count_manager.add_count(module) none_plugin_count_manager.reset(module)
logger.info( except Exception as e:
f"{module}:{plugin_name} 插件疑似已删除,加载{none_plugin_count_manager._max_count}次失败后将清除对应插件数据,当前次数:{none_plugin_count_manager._data[module]}") logger.error(f"清除插件数据错误 {type(e)}{e}")
else: plugins2settings_manager.save()
none_plugin_count_manager.reset(module) plugins2count_manager.save()
plugins2cd_manager.save()
plugins2block_manager.save()
plugins_manager.save()
none_plugin_count_manager.save() none_plugin_count_manager.save()

View File

@ -8,40 +8,32 @@ from services.log import logger
from utils.text_utils import prompt2cn from utils.text_utils import prompt2cn
from utils.utils import get_matchers from utils.utils import get_matchers
from utils.utils import scheduler from utils.utils import scheduler
from configs.path_config import DATA_PATH
from ruamel import yaml from ruamel import yaml
_yaml = YAML(typ="safe") _yaml = YAML(typ="safe")
def init_plugins_config(data_path): def init_plugins_config():
""" """
初始化插件数据配置 初始化插件数据配置
""" """
plugins2config_file = data_path / "configs" / "plugins2config.yaml" plugins2config_file = DATA_PATH / "configs" / "plugins2config.yaml"
plugins2config_file.parent.mkdir(parents=True, exist_ok=True) plugins2config_file.parent.mkdir(parents=True, exist_ok=True)
_data = {} _data = {}
if plugins2config_file.exists(): if plugins2config_file.exists():
_data = _yaml.load(open(plugins2config_file, "r", encoding="utf8")) _data = _yaml.load(open(plugins2config_file, "r", encoding="utf8"))
_matchers = get_matchers(True)
# 优先使用 metadata 数据 # 优先使用 metadata 数据
for matcher in _matchers: for matcher in [matcher for matcher in get_matchers(True) if matcher.plugin and matcher.plugin.module]:
_plugin = matcher.plugin _plugin = matcher.plugin
if not _plugin:
continue
metadata = _plugin.metadata metadata = _plugin.metadata
try: _module = _plugin.module
_module = _plugin.module
except AttributeError:
continue
plugin_version = None plugin_version = None
if metadata: if metadata:
plugin_version = metadata.extra.get("version") plugin_version = metadata.extra.get("version")
if not plugin_version: if not plugin_version and hasattr(_module, "__plugin_version__"):
try: plugin_version = _module.__getattribute__("__plugin_version__")
plugin_version = _module.__getattribute__("__plugin_version__")
except AttributeError:
pass
if metadata and metadata.config: if metadata and metadata.config:
plugin_configs = {} plugin_configs = {}
for key, value in metadata.config.__fields__.items(): for key, value in metadata.config.__fields__.items():
@ -61,7 +53,7 @@ def init_plugins_config(data_path):
_data.get(matcher.plugin_name) _data.get(matcher.plugin_name)
and _data[matcher.plugin_name].keys() != plugin_configs.keys() and _data[matcher.plugin_name].keys() != plugin_configs.keys()
) )
or plugin_version > plugins_manager.get(matcher.plugin_name)["version"] or plugin_version > plugins_manager.get(matcher.plugin_name).version
or matcher.plugin_name not in _data.keys() or matcher.plugin_name not in _data.keys()
): ):
for key in plugin_configs: for key in plugin_configs:
@ -94,16 +86,16 @@ def init_plugins_config(data_path):
_data = round_trip_load(open(plugins2config_file, encoding="utf8")) _data = round_trip_load(open(plugins2config_file, encoding="utf8"))
for plugin in _data.keys(): for plugin in _data.keys():
try: try:
plugin_name = plugins_manager.get(plugin)["plugin_name"] plugin_name = plugins_manager.get(plugin).plugin_name
except (AttributeError, TypeError): except (AttributeError, TypeError):
plugin_name = plugin plugin_name = plugin
_data[plugin].yaml_set_start_comment(plugin_name, indent=2) _data[plugin].yaml_set_start_comment(plugin_name, indent=2)
# 初始化未设置的管理员权限等级 # 初始化未设置的管理员权限等级
for k, v in Config.get_admin_level_data(): for k, v in Config.get_admin_level_data():
try: # try:
admin_manager.set_admin_level(k, v) admin_manager.set_admin_level(k, v)
except KeyError as e: # except KeyError as e:
raise KeyError(f"{e} ****** 请检查是否有插件加载失败 ******") # raise KeyError(f"{e} ****** 请检查是否有插件加载失败 ******")
# 存完插件基本设置 # 存完插件基本设置
with open(plugins2config_file, "w", encoding="utf8") as wf: with open(plugins2config_file, "w", encoding="utf8") as wf:
round_trip_dump( round_trip_dump(
@ -181,7 +173,7 @@ def _replace_config():
plugin_name = None plugin_name = None
if not plugin_name: if not plugin_name:
try: try:
plugin_name = plugins_manager.get(plugin)["plugin_name"] plugin_name = plugins_manager.get(plugin).plugin_name
except (AttributeError, TypeError): except (AttributeError, TypeError):
plugin_name = plugin plugin_name = plugin
plugin_name = ( plugin_name = (

View File

@ -3,6 +3,7 @@ from ruamel.yaml import YAML
from utils.manager import plugins_manager from utils.manager import plugins_manager
from utils.utils import get_matchers from utils.utils import get_matchers
from services.log import logger from services.log import logger
from configs.path_config import DATA_PATH
try: try:
import ujson as json import ujson as json
@ -13,17 +14,13 @@ except ModuleNotFoundError:
_yaml = YAML(typ="safe") _yaml = YAML(typ="safe")
def init_plugins_data(data_path): def init_plugins_data():
""" """
初始化插件数据信息 初始化插件数据信息
""" """
plugin2data_file = data_path / "manager" / "plugin_manager.json" plugin2data_file = DATA_PATH / "manager" / "plugin_manager.json"
plugin2data_file.parent.mkdir(parents=True, exist_ok=True) plugin2data_file.parent.mkdir(parents=True, exist_ok=True)
_data = {} for matcher in get_matchers(True):
if plugin2data_file.exists():
_data = json.load(open(plugin2data_file, "r", encoding="utf8"))
_matchers = get_matchers(True)
for matcher in _matchers:
_plugin = matcher.plugin _plugin = matcher.plugin
if not _plugin: if not _plugin:
continue continue
@ -31,27 +28,19 @@ def init_plugins_data(data_path):
try: try:
_module = _plugin.module _module = _plugin.module
except AttributeError: except AttributeError:
if matcher.plugin_name not in _data.keys(): if matcher.plugin_name not in plugins_manager.keys():
plugins_manager.add_plugin_data( plugins_manager.add_plugin_data(
matcher.plugin_name, matcher.plugin_name, error=True matcher.plugin_name, matcher.plugin_name, error=True
) )
else: else:
plugins_manager.set_module_data(matcher.plugin_name, "error", True) plugins_manager[matcher.plugin_name].error = True
plugin_data = plugins_manager.get(matcher.plugin_name)
if plugin_data:
plugins_manager.set_module_data(
matcher.plugin_name, "version", plugin_data.get("version")
)
else: else:
try: try:
plugin_version = None plugin_version = None
if metadata: if metadata:
plugin_version = metadata.extra.get("version") plugin_version = metadata.extra.get("version")
if not plugin_version: if not plugin_version and hasattr(_module, "__plugin_version__"):
try: plugin_version = _module.__getattribute__("__plugin_version__")
plugin_version = _module.__getattribute__("__plugin_version__")
except AttributeError:
pass
if metadata: if metadata:
plugin_name = metadata.name plugin_name = metadata.name
else: else:
@ -62,12 +51,10 @@ def init_plugins_data(data_path):
plugin_author = None plugin_author = None
if metadata: if metadata:
plugin_author = metadata.extra.get('author') plugin_author = metadata.extra.get('author')
try: if not plugin_author and hasattr(_module, "__plugin_author__"):
plugin_author = _module.__getattribute__("__plugin_author__") plugin_author = _module.__getattribute__("__plugin_author__")
except AttributeError:
pass
if matcher.plugin_name in plugins_manager.keys(): if matcher.plugin_name in plugins_manager.keys():
plugins_manager.set_module_data(matcher.plugin_name, "error", False) plugins_manager[matcher.plugin_name].error = False
if matcher.plugin_name not in plugins_manager.keys(): if matcher.plugin_name not in plugins_manager.keys():
plugins_manager.add_plugin_data( plugins_manager.add_plugin_data(
matcher.plugin_name, matcher.plugin_name,
@ -76,24 +63,21 @@ def init_plugins_data(data_path):
version=plugin_version, version=plugin_version,
) )
# metadata不检测version # metadata不检测version
elif isinstance(plugin_version, str) or plugins_manager[matcher.plugin_name]["version"] is None or ( elif isinstance(plugin_version, str) or plugins_manager[matcher.plugin_name].version is None or (
plugin_version is not None plugin_version is not None
and plugin_version > float(plugins_manager[matcher.plugin_name]["version"]) and plugin_version > float(plugins_manager[matcher.plugin_name].version)
): ):
plugins_manager.set_module_data( plugins_manager[matcher.plugin_name].plugin_name = plugin_name
matcher.plugin_name, "plugin_name", plugin_name plugins_manager[matcher.plugin_name].author = plugin_author
) plugins_manager[matcher.plugin_name].version = plugin_version
plugins_manager.set_module_data(matcher.plugin_name, "author", plugin_author) # if matcher.plugin_name in _data.keys():
plugins_manager.set_module_data( # plugins_manager[matcher.plugin_name].error = _data[matcher.plugin_name]["error"]
matcher.plugin_name, "version", plugin_version # plugins_manager.set_module_data(
) # matcher.plugin_name, "error", _data[matcher.plugin_name]["error"]
if matcher.plugin_name in _data.keys(): # )
plugins_manager.set_module_data( # plugins_manager.set_module_data(
matcher.plugin_name, "error", _data[matcher.plugin_name]["error"] # matcher.plugin_name, "plugin_name", _data[matcher.plugin_name]["plugin_name"]
) # )
plugins_manager.set_module_data(
matcher.plugin_name, "plugin_name", _data[matcher.plugin_name]["plugin_name"]
)
except Exception as e: except Exception as e:
logger.error(f"插件数据 {matcher.plugin_name} 加载发生错误 {type(e)}{e}") logger.error(f"插件数据 {matcher.plugin_name} 加载发生错误 {type(e)}{e}")
plugins_manager.save() plugins_manager.save()

View File

@ -1,27 +1,21 @@
from pathlib import Path
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
from utils.manager import ( from utils.manager import (
plugins2cd_manager, plugins2cd_manager,
plugins2block_manager, plugins2block_manager,
plugins2count_manager, plugins2count_manager,
) )
from utils.utils import get_matchers from utils.utils import get_matchers
from ruamel import yaml from configs.path_config import DATA_PATH
import nonebot import nonebot
_yaml = YAML(typ="safe") def init_plugins_cd_limit():
def init_plugins_cd_limit(data_path):
""" """
加载 cd 限制 加载 cd 限制
""" """
plugins2cd_file = data_path / "configs" / "plugins2cd.yaml" plugins2cd_file = DATA_PATH / "configs" / "plugins2cd.yaml"
plugins2cd_file.parent.mkdir(exist_ok=True, parents=True) plugins2cd_file.parent.mkdir(exist_ok=True, parents=True)
_data = {} _data = {}
_matchers = get_matchers() for matcher in get_matchers(True):
for matcher in _matchers:
if not plugins2cd_manager.get_plugin_cd_data(matcher.plugin_name): if not plugins2cd_manager.get_plugin_cd_data(matcher.plugin_name):
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name) _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
try: try:
@ -36,42 +30,19 @@ def init_plugins_cd_limit(data_path):
plugins2cd_manager.add_cd_limit( plugins2cd_manager.add_cd_limit(
"这是一个示例" "这是一个示例"
) )
_tmp_data = {"PluginCdLimit": plugins2cd_manager.get_data()} plugins2cd_manager.save()
with open(plugins2cd_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_data = round_trip_load(open(plugins2cd_file, encoding="utf8"))
_data["PluginCdLimit"].yaml_set_start_comment(
"""# 需要cd的功能
# 自定义的功能需要cd也可以在此配置
# key模块名称
# cdcd 时长(秒)
# status此限制的开关状态
# check_type'private'/'group'/'all',限制私聊/群聊/全部
# limit_type监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
# 示例:'user'用户N秒内触发1次'group'群N秒内触发1次
# rst回复的话可以添加[at][uname][nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(plugins2cd_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
plugins2cd_manager.reload_cd_limit() plugins2cd_manager.reload_cd_limit()
def init_plugins_block_limit(data_path): def init_plugins_block_limit():
""" """
加载阻塞限制 加载阻塞限制
""" """
plugins2block_file = data_path / "configs" / "plugins2block.yaml" plugins2block_file = DATA_PATH / "configs" / "plugins2block.yaml"
plugins2block_file.parent.mkdir(exist_ok=True, parents=True) plugins2block_file.parent.mkdir(exist_ok=True, parents=True)
_data = {} for matcher in get_matchers(True):
_matchers = get_matchers()
for matcher in _matchers:
if not plugins2block_manager.get_plugin_block_data(matcher.plugin_name): if not plugins2block_manager.get_plugin_block_data(matcher.plugin_name):
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name) _plugin = matcher.plugin
try: try:
_module = _plugin.module _module = _plugin.module
plugin_block_limit = _module.__getattribute__("__plugin_block_limit__") plugin_block_limit = _module.__getattribute__("__plugin_block_limit__")
@ -84,36 +55,15 @@ def init_plugins_block_limit(data_path):
plugins2block_manager.add_block_limit( plugins2block_manager.add_block_limit(
"这是一个示例" "这是一个示例"
) )
_tmp_data = {"PluginBlockLimit": plugins2block_manager.get_data()} plugins2block_manager.save()
with open(plugins2block_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_data = round_trip_load(open(plugins2block_file, encoding="utf8"))
_data["PluginBlockLimit"].yaml_set_start_comment(
"""# 用户调用阻塞
# 即 当用户调用此功能还未结束时
# 用发送消息阻止用户重复调用此命令直到该命令结束
# key模块名称
# status此限制的开关状态
# check_type'private'/'group'/'all',限制私聊/群聊/全部
# limit_type监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
# 示例:'user':阻塞用户,'group':阻塞群聊
# rst回复的话可以添加[at][uname][nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(plugins2block_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
plugins2block_manager.reload_block_limit() plugins2block_manager.reload_block_limit()
def init_plugins_count_limit(data_path): def init_plugins_count_limit():
""" """
加载次数限制 加载次数限制
""" """
plugins2count_file = data_path / "configs" / "plugins2count.yaml" plugins2count_file = DATA_PATH / "configs" / "plugins2count.yaml"
plugins2count_file.parent.mkdir(exist_ok=True, parents=True) plugins2count_file.parent.mkdir(exist_ok=True, parents=True)
_data = {} _data = {}
_matchers = get_matchers() _matchers = get_matchers()
@ -132,26 +82,5 @@ def init_plugins_count_limit(data_path):
plugins2count_manager.add_count_limit( plugins2count_manager.add_count_limit(
"这是一个示例" "这是一个示例"
) )
_tmp_data = {"PluginCountLimit": plugins2count_manager.get_data()} plugins2count_manager.save()
with open(plugins2count_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_data = round_trip_load(open(plugins2count_file, encoding="utf8"))
_data["PluginCountLimit"].yaml_set_start_comment(
"""# 命令每日次数限制
# 即 用户/群聊 每日可调用命令的次数 [数据内存存储,重启将会重置]
# 每日调用直到 00:00 刷新
# key模块名称
# max_count: 每日调用上限
# status此限制的开关状态
# limit_type监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
# 示例:'user':用户上限,'group':群聊上限
# rst回复的话可以添加[at][uname][nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(plugins2count_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
plugins2count_manager.reload_count_limit() plugins2count_manager.reload_count_limit()

View File

@ -1,24 +1,14 @@
from pathlib import Path
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
from utils.manager import plugins2settings_manager, admin_manager from utils.manager import plugins2settings_manager, admin_manager
from services.log import logger from services.log import logger
from utils.utils import get_matchers from utils.utils import get_matchers
from ruamel import yaml
import nonebot import nonebot
_yaml = YAML(typ="safe") def init_plugins_settings():
def init_plugins_settings(data_path: str):
""" """
初始化插件设置从插件中获取 __zx_plugin_name____plugin_cmd____plugin_settings__ 初始化插件设置从插件中获取 __zx_plugin_name____plugin_cmd____plugin_settings__
""" """
plugins2settings_file = data_path / "configs" / "plugins2settings.yaml"
plugins2settings_file.parent.mkdir(exist_ok=True, parents=True)
_matchers = get_matchers(True)
_tmp_module = {} _tmp_module = {}
_tmp = []
for x in plugins2settings_manager.keys(): for x in plugins2settings_manager.keys():
try: try:
_plugin = nonebot.plugin.get_plugin(x) _plugin = nonebot.plugin.get_plugin(x)
@ -33,12 +23,10 @@ def init_plugins_settings(data_path: str):
except (KeyError, AttributeError) as e: except (KeyError, AttributeError) as e:
logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}") logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
_tmp_module[x] = "" _tmp_module[x] = ""
for matcher in _matchers: for matcher in [x for x in get_matchers(True) if x.plugin]:
try: try:
if matcher.plugin_name not in plugins2settings_manager.keys(): if matcher.plugin_name not in plugins2settings_manager.keys():
_plugin = matcher.plugin _plugin = matcher.plugin
if not _plugin:
continue
metadata = _plugin.metadata metadata = _plugin.metadata
try: try:
_module = _plugin.module _module = _plugin.module
@ -46,22 +34,17 @@ def init_plugins_settings(data_path: str):
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.") logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.")
else: else:
try: try:
if metadata: plugin_name = metadata.name if metadata else _module.__getattribute__("__zx_plugin_name__")
plugin_name = metadata.name # 管理员命令
else:
plugin_name = _module.__getattribute__("__zx_plugin_name__")
if "[admin]" in plugin_name.lower(): if "[admin]" in plugin_name.lower():
try: level = 5
cmd = None
if hasattr(_module, "__plugin_settings__"):
admin_settings = _module.__getattribute__( admin_settings = _module.__getattribute__(
"__plugin_settings__" "__plugin_settings__"
) )
level = admin_settings["admin_level"] level = admin_settings.get("admin_level", 5)
cmd = admin_settings.get("cmd") cmd = admin_settings.get("cmd")
except (AttributeError, KeyError):
level = 5
cmd = None
if level is None:
level = 5
admin_manager.add_admin_plugin_settings( admin_manager.add_admin_plugin_settings(
matcher.plugin_name, cmd, level matcher.plugin_name, cmd, level
) )
@ -73,19 +56,18 @@ def init_plugins_settings(data_path: str):
): ):
continue continue
except AttributeError: except AttributeError:
if matcher.plugin_name not in _tmp: logger.warning(
logger.warning( f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载."
f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载." )
)
else: else:
_tmp_module[matcher.plugin_name] = plugin_name _tmp_module[matcher.plugin_name] = plugin_name
try: if hasattr(_module, "__plugin_settings__"):
plugin_settings = _module.__getattribute__( plugin_settings = _module.__getattribute__(
"__plugin_settings__" "__plugin_settings__"
) )
except AttributeError: else:
plugin_settings = {"cmd": [matcher.plugin_name, plugin_name]} plugin_settings = {"cmd": [matcher.plugin_name, plugin_name]}
if not plugin_settings.get("cost_gold"): if plugin_settings.get("cost_gold") is None:
plugin_settings["cost_gold"] = 0 plugin_settings["cost_gold"] = 0
if ( if (
plugin_settings.get("cmd") is not None plugin_settings.get("cmd") is not None
@ -100,12 +82,12 @@ def init_plugins_settings(data_path: str):
plugin_type = tuple( plugin_type = tuple(
plugins2settings_manager.get_plugin_data( plugins2settings_manager.get_plugin_data(
matcher.plugin_name matcher.plugin_name
)["plugin_type"] ).plugin_type
) )
else: else:
try: if hasattr(_module, "__plugin_type__"):
plugin_type = _module.__getattribute__("__plugin_type__") plugin_type = _module.__getattribute__("__plugin_type__")
except AttributeError: else:
plugin_type = ("normal",) plugin_type = ("normal",)
if plugin_settings and matcher.plugin_name: if plugin_settings and matcher.plugin_name:
plugins2settings_manager.add_plugin_settings( plugins2settings_manager.add_plugin_settings(
@ -115,26 +97,5 @@ def init_plugins_settings(data_path: str):
) )
except Exception as e: except Exception as e:
logger.error(f'{matcher.plugin_name} 初始化 plugin_settings 发生错误 {type(e)}{e}') logger.error(f'{matcher.plugin_name} 初始化 plugin_settings 发生错误 {type(e)}{e}')
_tmp.append(matcher.plugin_name) plugins2settings_manager.save()
_tmp_data = {"PluginSettings": plugins2settings_manager.get_data()}
with open(plugins2settings_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_data = round_trip_load(open(plugins2settings_file, encoding="utf8"))
_data["PluginSettings"].yaml_set_start_comment(
"""# 模块与对应命令和对应群权限
# 用于生成帮助图片 和 开关功能
# key模块名称
# level需要的群等级
# default_status加入群时功能的默认开关状态
# limit_superuser: 功能状态是否限制超级用户
# cmd: 关闭[cmd] 都会触发命令 关闭对应功能cmd列表第一个词为统计的功能名称
# plugin_type: 帮助类别 示例:('原神相关',) 或 ('原神相关', 1)1代表帮助命令列向排列否则为横向排列""",
indent=2,
)
for plugin in _data["PluginSettings"].keys():
_data["PluginSettings"][plugin].yaml_set_start_comment(
f"{plugin}{_tmp_module[plugin]}", indent=2
)
with open(plugins2settings_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
logger.info(f"已成功加载 {len(plugins2settings_manager.get_data())} 个非限制插件.") logger.info(f"已成功加载 {len(plugins2settings_manager.get_data())} 个非限制插件.")

View File

@ -122,8 +122,8 @@ async def _(event: GroupMessageEvent):
tmp = "" tmp = ""
data = plugins2settings_manager.get_data() data = plugins2settings_manager.get_data()
for module in data: for module in data:
if data[module]["level"] > level: if data[module].level > level:
plugin_name = data[module]["cmd"][0] plugin_name = data[module].cmd[0]
if plugin_name == "pixiv": if plugin_name == "pixiv":
plugin_name = "搜图 p站排行" plugin_name = "搜图 p站排行"
tmp += f"{plugin_name}\n" tmp += f"{plugin_name}\n"

View File

@ -67,7 +67,7 @@ async def _():
gl = [g["group_id"] for g in gl] gl = [g["group_id"] for g in gl]
msg_list, code = await get_epic_free(bot, "Group") msg_list, code = await get_epic_free(bot, "Group")
for g in gl: for g in gl:
if await group_manager.check_group_task_status(g, "epic_free_game"): if group_manager.check_group_task_status(g, "epic_free_game"):
try: try:
if msg_list and code == 200: if msg_list and code == 200:
await bot.send_group_forward_msg(group_id=g, messages=msg_list) await bot.send_group_forward_msg(group_id=g, messages=msg_list)

View File

@ -71,5 +71,5 @@ async def _():
if alc_img: if alc_img:
mes = "[[_task|genshin_alc]]" + alc_img + "\n ※ 黄历数据来源于 genshin.pub" mes = "[[_task|genshin_alc]]" + alc_img + "\n ※ 黄历数据来源于 genshin.pub"
for gid in gl: for gid in gl:
if await group_manager.check_group_task_status(gid, "genshin_alc"): if group_manager.check_group_task_status(gid, "genshin_alc"):
await bot.send_group_msg(group_id=int(gid), message="" + mes) await bot.send_group_msg(group_id=int(gid), message="" + mes)

View File

@ -172,7 +172,7 @@ async def generate_statistics_img(
data: dict, arg: str, name: str, plugin: str, day_index: int data: dict, arg: str, name: str, plugin: str, day_index: int
): ):
try: try:
plugin = plugins2settings_manager.get_plugin_data(plugin)['cmd'][0] plugin = plugins2settings_manager.get_plugin_data(plugin).cmd[0]
except (KeyError, IndexError): except (KeyError, IndexError):
pass pass
bar_graph = None bar_graph = None

View File

@ -107,8 +107,8 @@ async def _(
group_id = "total" group_id = "total"
user_id = str(event.user_id) user_id = str(event.user_id)
plugin_name = plugins2settings_manager.get_plugin_data(module) plugin_name = plugins2settings_manager.get_plugin_data(module)
if plugin_name and plugin_name.get('cmd'): if plugin_name and plugin_name.cmd:
plugin_name = plugin_name.get('cmd')[0] plugin_name = plugin_name.cmd[0]
check_exists_key(group_id, user_id, plugin_name) check_exists_key(group_id, user_id, plugin_name)
for data in [_prefix_count_dict, _prefix_user_count_dict]: for data in [_prefix_count_dict, _prefix_user_count_dict]:
data["total_statistics"]["total"][plugin_name] += 1 data["total_statistics"]["total"][plugin_name] += 1

View File

@ -23,11 +23,11 @@ gConfig.add_plugin_config("web-ui", "password", None, name="web-ui", help_="前
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
flag = False flag = False
for module in plugins2settings_manager.keys(): for module in plugins2settings_manager.keys():
if isinstance(plugins2settings_manager.get_plugin_data(module).get("cmd"), str): if isinstance(plugins2settings_manager.get_plugin_data(module).cmd, str):
plugins2settings_manager.set_module_data( plugins2settings_manager.set_module_data(
module, module,
"cmd", "cmd",
plugins2settings_manager.get_plugin_data(module).get("cmd").split(","), plugins2settings_manager.get_plugin_data(module).cmd.split(","),
False False
) )
flag = True flag = True

View File

@ -61,8 +61,8 @@ def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result:
) )
data["plugin_manager"] = PluginManager(**x) data["plugin_manager"] = PluginManager(**x)
if x := plugins2settings_manager.get(model): if x := plugins2settings_manager.get(model):
if x.get("cmd") and isinstance(x.get("cmd"), list): if x.cmd and isinstance(x.cmd, list):
x["cmd"] = ",".join(x["cmd"]) x.cmd = ",".join(x.cmd)
data["plugin_settings"] = PluginSettings(**x) data["plugin_settings"] = PluginSettings(**x)
if x := plugins2cd_manager.get(model): if x := plugins2cd_manager.get(model):
data["cd_limit"] = CdLimit(**x) data["cd_limit"] = CdLimit(**x)

View File

@ -10,8 +10,6 @@
"poetry.lock", "poetry.lock",
"pyproject.toml" "pyproject.toml"
], ],
"add_file": [ "add_file": [],
"resources/image/shop_icon"
],
"delete_file": [] "delete_file": []
} }

View File

@ -14,6 +14,9 @@ from .requests_manager import RequestManager
from configs.path_config import DATA_PATH from configs.path_config import DATA_PATH
# 管理员命令管理器
admin_manager = AdminManager()
# 群功能开关 | 群被动技能 | 群权限 管理 # 群功能开关 | 群被动技能 | 群权限 管理
group_manager: Optional[GroupManager] = GroupManager( group_manager: Optional[GroupManager] = GroupManager(
DATA_PATH / "manager" / "group_manager.json" DATA_PATH / "manager" / "group_manager.json"
@ -62,5 +65,3 @@ requests_manager: Optional[RequestManager] = RequestManager(
DATA_PATH / "manager" / "requests_manager.json" DATA_PATH / "manager" / "requests_manager.json"
) )
# 管理员命令管理器
admin_manager = AdminManager()

64
utils/manager/admin_manager.py Executable file → Normal file
View File

@ -1,5 +1,6 @@
from .data_class import StaticData from .models import AdminSetting
from typing import List, Optional from utils.manager.data_class import StaticData
from typing import List, Optional, Dict
class AdminManager(StaticData): class AdminManager(StaticData):
@ -9,60 +10,71 @@ class AdminManager(StaticData):
def __init__(self): def __init__(self):
super().__init__(None) super().__init__(None)
self._data: Dict[str, AdminSetting] = {}
def add_admin_plugin_settings(self, plugin: str, cmd: List[str], level: int): def add_admin_plugin_settings(self, plugin: str, cmd: List[str], level: int):
""" """
添加一个管理员命令 说明:
:param plugin: 模块 添加一个管理员命令
:param cmd: 别名 参数:
:param level: 等级 :param plugin: 模块
:param cmd: 别名
:param level: 等级
""" """
self._data[plugin] = { self._data[plugin] = AdminSetting(level=level, cmd=cmd)
"level": level,
"cmd": cmd,
}
def set_admin_level(self, plugin: str, level: int): def set_admin_level(self, plugin: str, level: int):
""" """
设置管理员命令等级 说明:
:param plugin: 模块名 设置管理员命令等级
:param level: 权限等级 参数:
:param plugin: 模块名
:param level: 权限等级
""" """
self._data[plugin]["level"] = level if plugin in self._data.keys():
self._data[plugin].level = level
def remove_admin_plugin_settings(self, plugin: str): def remove_admin_plugin_settings(self, plugin: str):
""" """
删除一个管理员命令 说明:
:param plugin: 模块名 删除一个管理员命令
参数:
:param plugin: 模块名
""" """
if plugin in self._data.keys(): if plugin in self._data.keys():
del self._data[plugin] del self._data[plugin]
def check(self, plugin: str, level: int) -> bool: def check(self, plugin: str, level: int) -> bool:
""" """
检查是否满足权限 说明:
:param plugin: 模块名 检查是否满足权限
:param level: 权限等级 参数:
:param plugin: 模块名
:param level: 权限等级
""" """
if plugin in self._data.keys(): if plugin in self._data.keys():
return level >= self._data[plugin]["level"] return level >= self._data[plugin].level
return True return True
def get_plugin_level(self, plugin: str) -> int: def get_plugin_level(self, plugin: str) -> int:
""" """
获取插件等级 说明:
:param plugin: 模块名 获取插件等级
参数:
:param plugin: 模块名
""" """
if plugin in self._data.keys(): if plugin in self._data.keys():
return self._data[plugin]["level"] return self._data[plugin].level
return 0 return 0
def get_plugin_module(self, cmd: str) -> Optional[str]: def get_plugin_module(self, cmd: str) -> Optional[str]:
""" """
根据 cmd 获取功能 modules 说明:
:param cmd: 命令 根据 cmd 获取功能 modules
参数:
:param cmd: 命令
""" """
for key in self._data.keys(): for key in self._data.keys():
if self._data[key].get("cmd") and cmd in self._data[key]["cmd"]: if self._data[key].cmd and cmd in self._data[key].cmd:
return key return key
return None return None

0
utils/manager/configs_manager.py Executable file → Normal file
View File

View File

@ -1,24 +1,29 @@
from typing import Union, Optional from typing import Union, Optional, TypeVar, Generic, Dict, NoReturn, Any
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML from ruamel.yaml import YAML
from ruamel import yaml from ruamel import yaml
import ujson as json import ujson as json
import copy import copy
from .models import *
_yaml = YAML(typ="safe") _yaml = YAML(typ="safe")
class StaticData: T = TypeVar("T", AdminSetting, BaseData, PluginBlock, PluginCd, PluginCount, PluginSetting, Plugin)
class StaticData(Generic[T]):
""" """
静态数据共享类 静态数据共享类
""" """
def __init__(self, file: Optional[Path]): def __init__(self, file: Optional[Path], load_file: bool = True):
self._data: dict = {} self._data: dict = {}
if file: if file:
file.parent.mkdir(exist_ok=True, parents=True) file.parent.mkdir(exist_ok=True, parents=True)
self.file = file self.file = file
if file.exists(): if file.exists() and load_file:
with open(file, "r", encoding="utf8") as f: with open(file, "r", encoding="utf8") as f:
if file.name.endswith("json"): if file.name.endswith("json"):
try: try:
@ -29,30 +34,39 @@ class StaticData:
elif file.name.endswith("yaml"): elif file.name.endswith("yaml"):
self._data = _yaml.load(f) self._data = _yaml.load(f)
def set(self, key, value): def set(self, key, value) -> NoReturn:
self._data[key] = value self._data[key] = value
self.save() self.save()
def set_module_data(self, module, key, value, auto_save: bool = True): def set_module_data(self, module, key, value, auto_save: bool = True) -> NoReturn:
if module in self._data.keys(): if module in self._data.keys():
self._data[module][key] = value self._data[module][key] = value
if auto_save: if auto_save:
self.save() self.save()
def get(self, key): def get(self, key) -> T:
return self._data.get(key) return self._data.get(key)
def keys(self): def keys(self) -> List[str]:
return self._data.keys() return self._data.keys()
def delete(self, key): def delete(self, key) -> NoReturn:
if self._data.get(key) is not None: if self._data.get(key) is not None:
del self._data[key] del self._data[key]
def get_data(self) -> dict: def get_data(self) -> Dict[str, T]:
return copy.deepcopy(self._data) return copy.deepcopy(self._data)
def save(self, path: Union[str, Path] = None): def dict(self) -> Dict[str, Any]:
temp = {}
for k, v in self._data.items():
try:
temp[k] = v.dict()
except AttributeError:
temp[k] = copy.deepcopy(v)
return temp
def save(self, path: Union[str, Path] = None) -> NoReturn:
path = path or self.file path = path or self.file
if isinstance(path, str): if isinstance(path, str):
path = Path(path) path = Path(path)
@ -61,26 +75,26 @@ class StaticData:
if path.name.endswith("yaml"): if path.name.endswith("yaml"):
yaml.dump(self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True) yaml.dump(self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True)
else: else:
json.dump(self._data, f, ensure_ascii=False, indent=4) json.dump(self.dict(), f, ensure_ascii=False, indent=4)
def reload(self): def reload(self) -> NoReturn:
if self.file.exists(): if self.file.exists():
if self.file.name.endswith("json"): if self.file.name.endswith("json"):
self._data: dict = json.load(open(self.file, "r", encoding="utf8")) self._data: dict = json.load(open(self.file, "r", encoding="utf8"))
elif self.file.name.endswith("yaml"): elif self.file.name.endswith("yaml"):
self._data: dict = _yaml.load(open(self.file, "r", encoding="utf8")) self._data: dict = _yaml.load(open(self.file, "r", encoding="utf8"))
def is_exists(self): def is_exists(self) -> bool:
return self.file.exists() return self.file.exists()
def is_empty(self): def is_empty(self) -> bool:
return bool(len(self._data)) return bool(len(self._data))
def __str__(self): def __str__(self) -> str:
return str(self._data) return str(self._data)
def __setitem__(self, key, value): def __setitem__(self, key, value) -> NoReturn:
self._data[key] = value self._data[key] = value
def __getitem__(self, key): def __getitem__(self, key) -> T:
return self._data[key] return self._data[key]

730
utils/manager/group_manager.py Executable file → Normal file
View File

@ -1,378 +1,352 @@
from typing import Optional, List, Union, Dict from typing import List, Union, Dict, Callable
from pathlib import Path from pathlib import Path
from .data_class import StaticData from .models import BaseData, BaseGroup
from utils.utils import get_matchers, get_bot from utils.manager.data_class import StaticData
from configs.config import Config from utils.utils import get_matchers, is_number
import nonebot from configs.config import Config
import nonebot
import ujson as json
Config.add_plugin_config(
"group_manager", "DEFAULT_GROUP_LEVEL", 5, help_="默认群权限", default_value=5
) Config.add_plugin_config(
"group_manager", "DEFAULT_GROUP_LEVEL", 5, help_="默认群权限", default_value=5
Config.add_plugin_config( )
"group_manager", "DEFAULT_GROUP_BOT_STATUS", True, help_="默认进群总开关状态", default_value=True
) Config.add_plugin_config(
"group_manager", "DEFAULT_GROUP_BOT_STATUS", True, help_="默认进群总开关状态", default_value=True
)
class GroupManager(StaticData):
"""
群权限 | 功能 | 总开关 | 聊天时间 管理器 def init_group(func: Callable):
""" """
说明:
def __init__(self, file: Path): 初始化群数据
super().__init__(file) 参数:
if not self._data: :param func: func
self._data = { """
"super": {"white_group_list": []}, def wrapper(*args, **kwargs):
"group_manager": {}, self = args[0]
} group_id = list(filter(lambda x: is_number(x), args[1:]))[0]
self._task = {} if self and group_id and not self._data.group_manager.get(str(group_id)):
self._data.group_manager[str(group_id)] = BaseGroup()
def block_plugin(self, module: str, group_id: int): return func(*args, **kwargs)
""" return wrapper
说明:
锁定插件
参数: def init_task(func: Callable):
:param module: 功能模块名 """
:param group_id: 群组None时为超级用户禁用 说明:
""" 初始化群被动
self._set_plugin_status(module, "block", group_id) 参数:
:param func: func
def unblock_plugin(self, module: str, group_id: int): """
""" def wrapper(*args, **kwargs):
说明: self = args[0]
解锁插件 group_id = str(args[1])
参数: task = args[2] if len(args) > 1 else None
:param module: 功能模块名 if group_id and task and self._data.group_manager[group_id].group_task_status.get(task) is None:
:param group_id: 群组 for task in self._data.task:
""" if self._data.group_manager[group_id].group_task_status.get(task) is None:
self._set_plugin_status(module, "unblock", group_id) self._data.group_manager[group_id].group_task_status[task] = Config.get_config('_task', f'DEFAULT_{task}', default=True)
for task in list(self._data.group_manager[group_id].group_task_status):
def turn_on_group_bot_status(self, group_id: int): if task not in self._data.task:
""" del self._data.group_manager[group_id].group_task_status[task]
说明: self.save()
开启群bot开关 return func(*args, **kwargs)
参数: return wrapper
:param group_id: 群号
"""
self._set_group_bot_status(group_id, True) class GroupManager(StaticData):
"""
def shutdown_group_bot_status(self, group_id: int): 群权限 | 功能 | 总开关 | 聊天时间 管理器
""" """
说明:
关闭群bot开关 def __init__(self, file: Path):
参数: super().__init__(file, False)
:param group_id: 群号 self._data = BaseData.parse_file(file) if file.exists() else BaseData()
"""
self._set_group_bot_status(group_id, False) def block_plugin(self, module: str, group_id: int, is_save: bool = True):
"""
def check_group_bot_status(self, group_id: int) -> bool: 说明:
""" 锁定插件
说明: 参数:
检查群聊bot总开关状态 :param module: 功能模块名
参数: :param group_id: 群组None时为超级用户禁用
:param group_id: 说明 :param is_save: 是否保存文件
""" """
group_id = str(group_id) self._set_plugin_status(module, "block", group_id, is_save)
if not self._data["group_manager"].get(group_id):
self._init_group(group_id) def unblock_plugin(self, module: str, group_id: int, is_save: bool = True):
if self._data["group_manager"][group_id].get("status") is None: """
default_group_bot_status = Config.get_config("group_manager", "DEFAULT_GROUP_BOT_STATUS") 说明:
if default_group_bot_status: 解锁插件
default_group_bot_status = True 参数:
self._data["group_manager"][group_id]["status"] = default_group_bot_status :param module: 功能模块名
return self._data["group_manager"][group_id]["status"] :param group_id: 群组
:param is_save: 是否保存文件
def set_group_level(self, group_id: int, level: int): """
""" self._set_plugin_status(module, "unblock", group_id, is_save)
说明:
设置群权限 def turn_on_group_bot_status(self, group_id: int):
参数: """
:param group_id: 群组 说明:
:param level: 权限等级 开启群bot开关
""" 参数:
group_id = str(group_id) :param group_id: 群号
if not self._data["group_manager"].get(group_id): """
self._init_group(group_id) self._set_group_bot_status(group_id, True)
self._data["group_manager"][group_id]["level"] = level
self.save() def shutdown_group_bot_status(self, group_id: int):
"""
def get_plugin_status(self, module: str, group_id: int) -> bool: 说明:
""" 关闭群bot开关
说明: 参数:
获取插件状态 :param group_id: 群号
参数: """
:param module: 功能模块名 self._set_group_bot_status(group_id, False)
:param group_id: 群组
""" @init_group
group_id = str(group_id) if group_id else group_id def check_group_bot_status(self, group_id: int) -> bool:
if not self._data["group_manager"].get(group_id): """
self._init_group(group_id) 说明:
return True 检查群聊bot总开关状态
if module in self._data["group_manager"][group_id]["close_plugins"]: 参数:
return False :param group_id: 说明
return True """
return self._data.group_manager[str(group_id)].status
def get_group_level(self, group_id: int) -> int:
""" @init_group
说明: def set_group_level(self, group_id: int, level: int):
获取群等级 """
参数: 说明:
:param group_id: 群号 设置群权限
""" 参数:
group_id = str(group_id) :param group_id: 群组
if not self._data["group_manager"].get(group_id): :param level: 权限等级
self._init_group(group_id) """
return self._data["group_manager"][group_id]["level"] self._data.group_manager[str(group_id)].level = level
self.save()
def check_group_is_white(self, group_id: int) -> bool:
""" @init_group
说明: def get_plugin_status(self, module: str, group_id: int) -> bool:
检测群聊是否在白名单 """
参数: 说明:
:param group_id: 群号 获取插件状态
""" 参数:
return group_id in self._data["super"]["white_group_list"] :param module: 功能模块名
:param group_id: 群组
def add_group_white_list(self, group_id: int): """
""" return module not in self._data.group_manager[str(group_id)].close_plugins
说明:
将群聊加入白名单 @init_group
参数: def get_group_level(self, group_id: int) -> int:
:param group_id: 群号 """
""" 说明:
if group_id not in self._data["super"]["white_group_list"]: 获取群等级
self._data["super"]["white_group_list"].append(group_id) 参数:
:param group_id: 群号
def delete_group_white_list(self, group_id: int): """
""" return self._data.group_manager[str(group_id)].level
说明:
将群聊从白名单中删除 def check_group_is_white(self, group_id: int) -> bool:
参数: """
:param group_id: 群号 说明:
""" 检测群聊是否在白名单
if group_id in self._data["super"]["white_group_list"]: 参数:
self._data["super"]["white_group_list"].remove(group_id) :param group_id: 群号
"""
def get_group_white_list(self) -> List[str]: return group_id in self._data.white_group
"""
说明: def add_group_white_list(self, group_id: int):
获取所有群白名单 """
""" 说明:
return self._data["super"]["white_group_list"] 将群聊加入白名单
参数:
def delete_group(self, group_id: int): :param group_id: 群号
""" """
说明: if group_id not in self._data.white_group:
删除群配置 self._data.white_group.append(group_id)
参数:
:param group_id: 群号 def delete_group_white_list(self, group_id: int):
""" """
if group_id in self._data["group_manager"]: 说明:
del self._data["group_manager"][str(group_id)] 将群聊从白名单中删除
if group_id in self._data["super"]["white_group_list"]: 参数:
self._data["super"]["white_group_list"].remove(group_id) :param group_id: 群号
self.save() """
if group_id in self._data.white_group:
async def open_group_task(self, group_id: int, task: str): self._data.white_group.remove(group_id)
"""
说明: def get_group_white_list(self) -> List[int]:
开启群被动技能 """
参数: 说明:
:param group_id: 群号 获取所有群白名单
:param task: 被动技能名称 """
""" return self._data.white_group
await self._set_group_task_status(group_id, task, True)
def load_task(self):
async def close_group_task(self, group_id: int, task: str): """
""" 说明:
说明: 加载被动技能
关闭群被动技能 """
参数: for matcher in get_matchers(True):
:param group_id: 群号 _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
:param task: 被动技能名称 try:
""" _module = _plugin.module
await self._set_group_task_status(group_id, task, False) plugin_task = _module.__getattribute__("__plugin_task__")
for key in plugin_task.keys():
async def check_group_task_status(self, group_id: int, task: str) -> bool: if key in self._data.task.keys():
""" raise ValueError(f"plugin_task{key} 已存在!")
说明: self._data.task[key] = plugin_task[key]
查看群被动技能状态 except AttributeError:
参数: pass
:param group_id: 群号
:param task: 被动技能名称 @init_group
""" def delete_group(self, group_id: int):
group_id = str(group_id) """
if ( 说明:
not self._data["group_manager"][group_id].get("group_task_status") 删除群配置
or self._data["group_manager"][group_id]["group_task_status"].get(task) 参数:
is None :param group_id: 群号
): """
await self.init_group_task(group_id) if group_id in self._data.white_group:
return self._data["group_manager"][group_id]["group_task_status"][task] self._data.white_group.remove(group_id)
self.save()
def get_task_data(self) -> Dict[str, str]:
""" def open_group_task(self, group_id: int, task: str):
说明: """
获取所有被动任务 说明:
""" 开启群被动技能
return self._task 参数:
:param group_id: 群号
async def group_task_status(self, group_id: int) -> str: :param task: 被动技能名称
""" """
说明: self._set_group_group_task_status(group_id, task, True)
查看群被全部动技能状态
参数: def close_group_task(self, group_id: int, task: str):
:param group_id: 群号 """
""" 说明:
x = "[群被动技能]:\n" 关闭群被动技能
group_id = str(group_id) 参数:
if not self._data["group_manager"][group_id].get("group_task_status"): :param group_id: 群号
await self.init_group_task(group_id) :param task: 被动技能名称
for key in self._data["group_manager"][group_id]["group_task_status"].keys(): """
x += f'{self._task[key]}{"" if await self.check_group_task_status(int(group_id), key) else "×"}\n' self._set_group_group_task_status(group_id, task, False)
return x[:-1]
@init_task
async def _set_group_task_status(self, group_id: int, task: str, status: bool): def check_group_task_status(self, group_id: int, task: str) -> bool:
""" """
说明: 说明:
管理群被动技能状态 查看群被动技能状态
参数: 参数:
:param group_id: 群号 :param group_id: 群号
:param task: 被动技能 :param task: 被动技能名称
:param status: 状态 """
""" return self._data.group_manager[str(group_id)].group_task_status.get(task, False)
group_id = str(group_id)
if not self._data["group_manager"].get(group_id): def get_task_data(self) -> Dict[str, str]:
self._init_group(group_id) """
if ( 说明:
not self._data["group_manager"][group_id].get("group_task_status") 获取所有被动任务
or self._data["group_manager"][group_id]["group_task_status"].get(task) """
is None return self._data.task
):
await self.init_group_task(group_id) @init_task
self._data["group_manager"][group_id]["group_task_status"][task] = status def group_group_task_status(self, group_id: int) -> str:
self.save() """
说明:
async def init_group_task(self, group_id: Optional[Union[int, str]] = None): 查看群被全部动技能状态
""" 参数:
说明: :param group_id: 群号
初始化群聊 被动技能 状态 """
""" x = "[群被动技能]:\n"
if not self._task: group_id = str(group_id)
_m = [] for key in self._data.group_manager[group_id].group_task_status.keys():
for matcher in get_matchers(): x += f'{self._data.task[key]}{"" if self.check_group_task_status(int(group_id), key) else "×"}\n'
if matcher.plugin_name not in _m: return x[:-1]
_m.append(matcher.plugin_name)
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name) @init_task
try: @init_group
_module = _plugin.module def _set_group_group_task_status(self, group_id: int, task: str, status: bool):
plugin_task = _module.__getattribute__("__plugin_task__") """
for key in plugin_task.keys(): 说明:
if key in self._task.keys(): 管理群被动技能状态
raise ValueError(f"plugin_task{key} 已存在!") 参数:
self._task[key] = plugin_task[key] :param group_id: 群号
except AttributeError: :param task: 被动技能
pass :param status: 状态
bot = get_bot() """
if bot or group_id: self._data.group_manager[str(group_id)].group_task_status[task] = status
if group_id: self.save()
_group_list = [group_id]
else: @init_group
_group_list = [x["group_id"] for x in await bot.get_group_list()] def _set_plugin_status(
for group_id in _group_list: self,
group_id = str(group_id) module: str,
if not self._data["group_manager"].get(group_id): status: str,
self._init_group(group_id) group_id: int,
if not self._data["group_manager"][group_id].get("group_task_status"): is_save: bool
self._data["group_manager"][group_id]["group_task_status"] = {} ):
for task in self._task: """
if ( 说明:
self._data["group_manager"][group_id]["group_task_status"].get( 设置功能开关状态
task 参数:
) :param module: 功能模块名
is None :param status: 功能状态
): :param group_id: 群组
self._data["group_manager"][group_id]["group_task_status"][ :param is_save: 是否保存
task """
] = Config.get_config('_task', f'DEFAULT_{task}', default=True) group_id = str(group_id) if group_id else group_id
for task in list( if status == "block":
self._data["group_manager"][group_id]["group_task_status"] if module not in self._data.group_manager[group_id].close_plugins:
): self._data.group_manager[group_id].close_plugins.append(module)
if task not in self._task: else:
del self._data["group_manager"][group_id]["group_task_status"][ if module in self._data.group_manager[group_id].close_plugins:
task self._data.group_manager[group_id].close_plugins.remove(module)
] if is_save:
self.save() self.save()
def _set_plugin_status( @init_group
self, def _set_group_bot_status(self, group_id: Union[int, str], status: bool):
module: str, """
status: str, 说明:
group_id: int, 设置群聊bot总开关
): 参数:
""" :param group_id: 群号
说明: :param status: 开关状态
设置功能开关状态 """
参数: self._data.group_manager[str(group_id)].status = status
:param module: 功能模块名 self.save()
:param status: 功能状态
:param group_id: 群组 def reload(self):
""" if self.file.exists():
group_id = str(group_id) if group_id else group_id t = self._data.task
if not self._data["group_manager"].get(group_id): self._data = BaseData.parse_file(self.file)
self._init_group(group_id) self._data.task = t
if status == "block":
if module not in self._data["group_manager"][group_id]["close_plugins"]: def save(self, path: Union[str, Path] = None):
self._data["group_manager"][group_id]["close_plugins"].append(module) """
else: 说明:
if module in self._data["group_manager"][group_id]["close_plugins"]: 保存文件
self._data["group_manager"][group_id]["close_plugins"].remove(module) 参数:
self.save() :param path: 路径文件
"""
def _init_group(self, group_id: str): path = path or self.file
""" if isinstance(path, str):
说明: path = Path(path)
初始化群数据 if path:
参数: dict_data = self._data.dict()
:param group_id: 群号 del dict_data["task"]
""" with open(path, "w", encoding="utf8") as f:
default_group_level = Config.get_config("group_manager", "DEFAULT_GROUP_LEVEL") json.dump(dict_data, f, ensure_ascii=False, indent=4)
if default_group_level is None:
default_group_level = 5 # def get_super_old_data(self) -> Optional[dict]:
default_group_bot_status = Config.get_config("group_manager", "DEFAULT_GROUP_BOT_STATUS") # """
if default_group_bot_status: # 说明:
default_group_bot_status = True # 获取旧数据,平时使用请不要调用
if not self._data["group_manager"].get(group_id): # """
self._data["group_manager"][group_id] = { # if self._data["super"].get("close_plugins"):
"level": default_group_level, # _x = self._data["super"].get("close_plugins")
"status": default_group_bot_status, # del self._data["super"]["close_plugins"]
"close_plugins": [], # return _x
"group_task_status": {}, # return None
}
def _set_group_bot_status(self, group_id: Union[int, str], status: bool):
"""
说明:
设置群聊bot总开关
参数:
:param group_id: 群号
:param status: 开关状态
"""
group_id = str(group_id)
if not self._data["group_manager"].get(group_id):
self._init_group(group_id)
self._data["group_manager"][group_id]["status"] = status
self.save()
def get_super_old_data(self) -> Optional[dict]:
"""
说明:
获取旧数据平时使用请不要调用
"""
if self._data["super"].get("close_plugins"):
_x = self._data["super"].get("close_plugins")
del self._data["super"]["close_plugins"]
return _x
return None

95
utils/manager/models.py Normal file
View File

@ -0,0 +1,95 @@
from typing import List, Optional, Dict, Literal, Tuple, Union
from pydantic import BaseModel
from configs.config import Config
class AdminSetting(BaseModel):
"""
管理员设置
"""
level: int
cmd: Optional[List[str]]
class BaseGroup(BaseModel):
"""
基础群聊信息
"""
level: int = Config.get_config("group_manager", "DEFAULT_GROUP_LEVEL") # 群等级
status: bool = Config.get_config(
"group_manager", "DEFAULT_GROUP_BOT_STATUS"
) # 总开关状态
close_plugins: List[str] = [] # 已关闭插件
group_task_status: Dict[str, bool] = {} # 被动状态
class BaseData(BaseModel):
"""
群基本信息
"""
white_group: List[int] = [] # 白名单
group_manager: Dict[str, BaseGroup] = {} # 群组管理
task: Dict[str, str] = {} # 被动任务 【英文:中文】
class PluginBlock(BaseModel):
"""
插件阻断
"""
status: bool # 限制状态
check_type: Literal["private", "group", "all"] # 检查类型
limit_type: Literal["user", "group"] # 监听对象
rst: Optional[str] # 阻断时回复
class PluginCd(BaseModel):
"""
插件阻断
"""
cd: int # cd
status: bool # 限制状态
check_type: Literal["private", "group", "all"] # 检查类型
limit_type: Literal["user", "group"] # 监听对象
rst: Optional[str] # 阻断时回复
class PluginCount(BaseModel):
"""
插件阻断
"""
max_count: int # 次数
status: bool # 限制状态
limit_type: Literal["user", "group"] # 监听对象
rst: Optional[str] # 阻断时回复
class PluginSetting(BaseModel):
"""
插件设置
"""
cmd: List[str] = [] # 命令 或 命令别名
default_status: bool = True # 默认开关状态
level: int = 5 # 功能权限等级
limit_superuser: bool = False # 功能状态是否限制超级用户
plugin_type: Tuple[Union[str, int], ...] = ("normal",) # 插件类型
cost_gold: int = 0 # 需要消费的金币
class Plugin(BaseModel):
"""
插件数据
"""
plugin_name: str # 模块名
status: Optional[bool] = True # 开关状态
error: Optional[bool] = False # 是否加载报错
block_type: Optional[str] = None # 关闭类型
author: Optional[str] = None # 作者
version: Optional[int] = None # 版本

94
utils/manager/none_plugin_count_manager.py Executable file → Normal file
View File

@ -1,47 +1,47 @@
from .data_class import StaticData from utils.manager.data_class import StaticData
from typing import Optional from typing import Optional
from pathlib import Path from pathlib import Path
class NonePluginCountManager(StaticData): class NonePluginCountManager(StaticData):
""" """
插件加载容忍管理器当连续 max_count 次插件加载视为删除插件清楚数据 插件加载容忍管理器当连续 max_count 次插件加载视为删除插件清楚数据
""" """
def __init__(self, file: Optional[Path], max_count: int = 5): def __init__(self, file: Optional[Path], max_count: int = 5):
""" """
:param file: 存储路径 :param file: 存储路径
:param max_count: 容忍最大次数 :param max_count: 容忍最大次数
""" """
super().__init__(file) super().__init__(file)
if not self._data: if not self._data:
self._data = {} self._data = {}
self._max_count = max_count self._max_count = max_count
def add_count(self, module: str, count: int = 1): def add_count(self, module: str, count: int = 1):
""" """
添加次数 添加次数
:param module: 模块 :param module: 模块
:param count: 次数无特殊情况均为 1 :param count: 次数无特殊情况均为 1
""" """
if module not in self._data.keys(): if module not in self._data.keys():
self._data[module] = count self._data[module] = count
else: else:
self._data[module] += count self._data[module] += count
def reset(self, module: str): def reset(self, module: str):
""" """
重置次数 重置次数
:param module: 模块 :param module: 模块
""" """
if module in self._data.keys(): if module in self._data.keys():
self._data[module] = 0 self._data[module] = 0
def check(self, module: str): def check(self, module: str):
""" """
检查容忍次数是否到达最大值 检查容忍次数是否到达最大值
:param module: 模块 :param module: 模块
""" """
if module in self._data.keys(): if module in self._data.keys():
return self._data[module] >= self._max_count return self._data[module] >= self._max_count
return False return False

153
utils/manager/plugins2block_manager.py Executable file → Normal file
View File

@ -1,11 +1,12 @@
from typing import Optional, Dict from typing import Optional, Dict, Literal, Union
from .data_class import StaticData from utils.manager.data_class import StaticData
from services.log import logger from services.log import logger
from utils.utils import UserBlockLimiter from utils.utils import UserBlockLimiter
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML from ruamel import yaml
from .models import PluginBlock
yaml = YAML(typ="safe") _yaml = yaml.YAML(typ="safe")
class Plugins2blockManager(StaticData): class Plugins2blockManager(StaticData):
@ -14,53 +15,45 @@ class Plugins2blockManager(StaticData):
""" """
def __init__(self, file: Path): def __init__(self, file: Path):
self.file = file super().__init__(file, False)
super().__init__(None)
self._block_limiter: Dict[str, UserBlockLimiter] = {} self._block_limiter: Dict[str, UserBlockLimiter] = {}
if file.exists(): self.__load_file()
with open(file, "r", encoding="utf8") as f:
self._data = yaml.load(f)
if "PluginBlockLimit" in self._data.keys():
self._data = self._data["PluginBlockLimit"] or {}
def add_block_limit( def add_block_limit(
self, self,
plugin: str, plugin: str,
*, *,
status: Optional[bool] = True, status: Optional[bool] = True,
check_type: Optional[str] = "all", check_type: Literal["private", "group", "all"] = "all",
limit_type: Optional[str] = "user", limit_type: Literal["user", "group"] = "user",
rst: Optional[str] = None, rst: Optional[str] = None,
**kwargs # 用于接收额外实参
): ):
""" """
添加插件调用 block 限制 说明:
:param plugin: 插件模块名称 添加插件调用 block 限制
:param status: 默认开关状态 参数:
:param check_type: 检查类型 'private'/'group'/'all'限制私聊/群聊/全部 :param plugin: 插件模块名称
:param limit_type: 限制类型 监听对象以user_id或group_id作为键来限制'user'用户id'group'群id :param status: 默认开关状态
:param rst: 回复的话为空则不回复 :param check_type: 检查类型 'private'/'group'/'all'限制私聊/群聊/全部
:param limit_type: 限制类型 监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
:param rst: 回复的话为空则不回复
""" """
status = status or True
check_type = check_type or "all"
limit_type = limit_type or "user"
if check_type not in ["all", "group", "private"]: if check_type not in ["all", "group", "private"]:
raise ValueError( raise ValueError(
f"{plugin} 添加block限制错误check_type 必须为 'private'/'group'/'all'" f"{plugin} 添加block限制错误check_type 必须为 'private'/'group'/'all'"
) )
if limit_type not in ["user", "group"]: if limit_type not in ["user", "group"]:
raise ValueError(f"{plugin} 添加block限制错误limit_type 必须为 'user'/'group'") raise ValueError(f"{plugin} 添加block限制错误limit_type 必须为 'user'/'group'")
self._data[plugin] = { self._data[plugin] = PluginBlock(
"status": status, status=status, check_type=check_type, limit_type=limit_type, rst=rst
"check_type": check_type, )
"limit_type": limit_type,
"rst": rst,
}
def get_plugin_block_data(self, plugin: str) -> Optional[dict]: def get_plugin_block_data(self, plugin: str) -> Optional[PluginBlock]:
""" """
获取插件block数据 说明:
:param plugin: 模块名 获取插件block数据
参数:
:param plugin: 模块名
""" """
if self.check_plugin_block_status(plugin): if self.check_plugin_block_status(plugin):
return self._data[plugin] return self._data[plugin]
@ -68,16 +61,20 @@ class Plugins2blockManager(StaticData):
def check_plugin_block_status(self, plugin: str) -> bool: def check_plugin_block_status(self, plugin: str) -> bool:
""" """
检测插件是否有 block 说明:
:param plugin: 模块名 检测插件是否有 block
参数:
:param plugin: 模块名
""" """
return plugin in self._data.keys() and self._data[plugin]["status"] return plugin in self._data.keys() and self._data[plugin].status
def check(self, id_: int, plugin: str) -> bool: def check(self, id_: int, plugin: str) -> bool:
""" """
检查 block 说明:
:param plugin: 模块名 检查 block
:param id_: 限制 id 参数:
:param id_: 限制 id
:param plugin: 模块名
""" """
if self._block_limiter.get(plugin): if self._block_limiter.get(plugin):
return self._block_limiter[plugin].check(id_) return self._block_limiter[plugin].check(id_)
@ -85,26 +82,30 @@ class Plugins2blockManager(StaticData):
def set_true(self, id_: int, plugin: str): def set_true(self, id_: int, plugin: str):
""" """
对插件 block 说明:
:param plugin: 模块名 对插件 block
:param id_: 限制 id 参数:
:param id_: 限制 id
:param plugin: 模块名
""" """
if self._block_limiter.get(plugin): if self._block_limiter.get(plugin):
self._block_limiter[plugin].set_true(id_) self._block_limiter[plugin].set_true(id_)
def set_false(self, id_: int, plugin: str): def set_false(self, id_: int, plugin: str):
""" """
对插件 unblock 说明:
:param plugin: 模块名 对插件 unblock
:param id_: 限制 id 参数:
:param plugin: 模块名
:param id_: 限制 id
""" """
if self._block_limiter.get(plugin): if self._block_limiter.get(plugin):
self._block_limiter[plugin].set_false(id_) self._block_limiter[plugin].set_false(id_)
def reload_block_limit(self): def reload_block_limit(self):
""" """
加载 block 限制器 说明:
:return: 加载 block 限制器
""" """
for plugin in self._data: for plugin in self._data:
if self.check_plugin_block_status(plugin): if self.check_plugin_block_status(plugin):
@ -113,10 +114,62 @@ class Plugins2blockManager(StaticData):
def reload(self): def reload(self):
""" """
重载本地数据 说明:
重载本地数据
""" """
self.__load_file()
self.reload_block_limit()
def save(self, path: Union[str, Path] = None):
"""
说明:
保存文件
参数:
:param path: 文件路径
"""
path = path or self.file
if isinstance(path, str):
path = Path(path)
if path:
with open(path, "w", encoding="utf8") as f:
yaml.dump(
{"PluginBlockLimit": self.dict()},
f,
indent=2,
Dumper=yaml.RoundTripDumper,
allow_unicode=True,
)
_data = yaml.round_trip_load(open(path, encoding="utf8"))
_data["PluginBlockLimit"].yaml_set_start_comment(
"""# 用户调用阻塞
# 即 当用户调用此功能还未结束时
# 用发送消息阻止用户重复调用此命令直到该命令结束
# key模块名称
# status此限制的开关状态
# check_type'private'/'group'/'all',限制私聊/群聊/全部
# limit_type监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
# 示例:'user':阻塞用户,'group':阻塞群聊
# rst回复的话可以添加[at][uname][nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(path, "w", encoding="utf8") as wf:
yaml.round_trip_dump(
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
def __load_file(self):
"""
说明:
读取配置文件
"""
self._data: Dict[str, PluginBlock] = {}
if self.file.exists(): if self.file.exists():
with open(self.file, "r", encoding="utf8") as f: with open(self.file, "r", encoding="utf8") as f:
self._data: dict = yaml.load(f) temp = yaml.round_trip_load(f)
self._data = self._data["PluginBlockLimit"] if "PluginBlockLimit" in temp.keys():
self.reload_block_limit() for k, v in temp["PluginBlockLimit"].items():
self._data[k] = PluginBlock.parse_obj(v)

167
utils/manager/plugins2cd_manager.py Executable file → Normal file
View File

@ -1,11 +1,12 @@
from typing import Optional, Dict from typing import Optional, Dict, Literal, Union
from .data_class import StaticData from utils.manager.data_class import StaticData
from utils.utils import FreqLimiter from utils.utils import FreqLimiter
from services.log import logger from services.log import logger
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML from ruamel import yaml
from .models import PluginCd
yaml = YAML(typ="safe") _yaml = yaml.YAML(typ="safe")
class Plugins2cdManager(StaticData): class Plugins2cdManager(StaticData):
@ -14,16 +15,9 @@ class Plugins2cdManager(StaticData):
""" """
def __init__(self, file: Path): def __init__(self, file: Path):
self.file = file super().__init__(file, False)
super().__init__(None)
self._freq_limiter: Dict[str, FreqLimiter] = {} self._freq_limiter: Dict[str, FreqLimiter] = {}
if file.exists(): self.__load_file()
with open(file, "r", encoding="utf8") as f:
self._data = yaml.load(f)
if "PluginCdLimit" in self._data.keys():
self._data = (
self._data["PluginCdLimit"] if self._data["PluginCdLimit"] else {}
)
def add_cd_limit( def add_cd_limit(
self, self,
@ -31,42 +25,35 @@ class Plugins2cdManager(StaticData):
*, *,
cd: Optional[int] = 5, cd: Optional[int] = 5,
status: Optional[bool] = True, status: Optional[bool] = True,
check_type: Optional[str] = "all", check_type: Literal["private", "group", "all"] = "all",
limit_type: Optional[str] = "user", limit_type: Literal["user", "group"] = "user",
rst: Optional[str] = None, rst: Optional[str] = None,
**kwargs # 用于接收额外实参
): ):
""" """
添加插件调用 cd 限制 说明:
:param plugin: 插件模块名称 添加插件调用 cd 限制
:param cd: cd 时长 参数:
:param status: 默认开关状态 :param plugin: 插件模块名称
:param check_type: 检查类型 'private'/'group'/'all'限制私聊/群聊/全部 :param cd: cd 时长
:param limit_type: 限制类型 监听对象以user_id或group_id作为键来限制'user'用户id'group'群id :param status: 默认开关状态
:param rst: 回复的话为空则不回复 :param check_type: 检查类型 'private'/'group'/'all'限制私聊/群聊/全部
:param limit_type: 限制类型 监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
:param rst: 回复的话为空则不回复
""" """
cd = cd or 5
status = status or True
check_type = check_type or "all"
limit_type = limit_type or "user"
if check_type not in ["all", "group", "private"]: if check_type not in ["all", "group", "private"]:
raise ValueError( raise ValueError(
f"{plugin} 添加cd限制错误check_type 必须为 'private'/'group'/'all'" f"{plugin} 添加cd限制错误check_type 必须为 'private'/'group'/'all'"
) )
if limit_type not in ["user", "group"]: if limit_type not in ["user", "group"]:
raise ValueError(f"{plugin} 添加cd限制错误limit_type 必须为 'user'/'group'") raise ValueError(f"{plugin} 添加cd限制错误limit_type 必须为 'user'/'group'")
self._data[plugin] = { self._data[plugin] = PluginCd(cd=cd, status=status, check_type=check_type, limit_type=limit_type, rst=rst)
"cd": cd,
"status": status,
"check_type": check_type,
"limit_type": limit_type,
"rst": rst,
}
def get_plugin_cd_data(self, plugin: str) -> Optional[dict]: def get_plugin_cd_data(self, plugin: str) -> Optional[PluginCd]:
""" """
获取插件cd数据 说明:
:param plugin: 模块名 获取插件cd数据
参数:
:param plugin: 模块名
""" """
if self.check_plugin_cd_status(plugin): if self.check_plugin_cd_status(plugin):
return self._data[plugin] return self._data[plugin]
@ -74,20 +61,24 @@ class Plugins2cdManager(StaticData):
def check_plugin_cd_status(self, plugin: str) -> bool: def check_plugin_cd_status(self, plugin: str) -> bool:
""" """
检测插件是否有 cd 说明:
:param plugin: 模块名 检测插件是否有 cd
参数:
:param plugin: 模块名
""" """
return ( return (
plugin in self._data.keys() plugin in self._data.keys()
and self._data[plugin]["cd"] > 0 and self._data[plugin].cd > 0
and self._data[plugin]["status"] and self._data[plugin].status
) )
def check(self, plugin: str, id_: int) -> bool: def check(self, plugin: str, id_: int) -> bool:
""" """
检查 cd 说明:
:param plugin: 模块名 检查 cd
:param id_: 限制 id 参数:
:param plugin: 模块名
:param id_: 限制 id
""" """
if self._freq_limiter.get(plugin): if self._freq_limiter.get(plugin):
return self._freq_limiter[plugin].check(id_) return self._freq_limiter[plugin].check(id_)
@ -95,42 +86,96 @@ class Plugins2cdManager(StaticData):
def start_cd(self, plugin: str, id_: int, cd: int = 0): def start_cd(self, plugin: str, id_: int, cd: int = 0):
""" """
开始cd 说明:
:param plugin: 模块名 开始cd
:param id_: cd 限制类型 参数:
:param cd: cd 时长 :param plugin: 模块名
:return: :param id_: cd 限制类型
:param cd: cd 时长
""" """
if self._freq_limiter.get(plugin): if self._freq_limiter.get(plugin):
self._freq_limiter[plugin].start_cd(id_, cd) self._freq_limiter[plugin].start_cd(id_, cd)
def get_plugin_data(self, plugin: str) -> dict: def get_plugin_data(self, plugin: str) -> Optional[PluginCd]:
""" """
获取单个模块限制数据 说明:
:param plugin: 模块名 获取单个模块限制数据
参数:
:param plugin: 模块名
""" """
if self._data.get(plugin) is not None: if self._data.get(plugin):
return self._data.get(plugin) return self._data.get(plugin)
return {}
def reload_cd_limit(self): def reload_cd_limit(self):
""" """
加载 cd 限制器 说明:
:return: 加载 cd 限制器
""" """
for plugin in self._data: for plugin in self._data:
if self.check_plugin_cd_status(plugin): if self.check_plugin_cd_status(plugin):
self._freq_limiter[plugin] = FreqLimiter( self._freq_limiter[plugin] = FreqLimiter(
self.get_plugin_cd_data(plugin)["cd"] self.get_plugin_cd_data(plugin).cd
) )
logger.info(f"已成功加载 {len(self._freq_limiter)} 个Cd限制.") logger.info(f"已成功加载 {len(self._freq_limiter)} 个Cd限制.")
def reload(self): def reload(self):
""" """
重载本地数据 说明:
重载本地数据
""" """
self.__load_file()
self.reload_cd_limit()
def save(self, path: Union[str, Path] = None):
"""
说明:
保存文件
参数:
:param path: 文件路径
"""
path = path or self.file
if isinstance(path, str):
path = Path(path)
if path:
with open(path, "w", encoding="utf8") as f:
yaml.dump(
{"PluginCdLimit": self.dict()},
f,
indent=2,
Dumper=yaml.RoundTripDumper,
allow_unicode=True,
)
_data = yaml.round_trip_load(open(path, encoding="utf8"))
_data["PluginCdLimit"].yaml_set_start_comment(
"""# 需要cd的功能
# 自定义的功能需要cd也可以在此配置
# key模块名称
# cdcd 时长(秒)
# status此限制的开关状态
# check_type'private'/'group'/'all',限制私聊/群聊/全部
# limit_type监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
# 示例:'user'用户N秒内触发1次'group'群N秒内触发1次
# rst回复的话可以添加[at][uname][nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(path, "w", encoding="utf8") as wf:
yaml.round_trip_dump(
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
def __load_file(self):
"""
说明:
读取配置文件
"""
self._data: Dict[str, PluginCd] = {}
if self.file.exists(): if self.file.exists():
with open(self.file, "r", encoding="utf8") as f: with open(self.file, "r", encoding="utf8") as f:
self._data: dict = yaml.load(f) temp = _yaml.load(f)
self._data = self._data["PluginCdLimit"] if "PluginCdLimit" in temp.keys():
self.reload_cd_limit() for k, v in temp["PluginCdLimit"].items():
self._data[k] = PluginCd.parse_obj(v)

156
utils/manager/plugins2count_manager.py Executable file → Normal file
View File

@ -1,11 +1,12 @@
from typing import Optional, Dict from typing import Optional, Dict, Literal, Union
from .data_class import StaticData from utils.manager.data_class import StaticData
from utils.utils import DailyNumberLimiter from utils.utils import DailyNumberLimiter
from services.log import logger from services.log import logger
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML from ruamel import yaml
from .models import PluginCount
yaml = YAML(typ="safe") _yaml = yaml.YAML(typ="safe")
class Plugins2countManager(StaticData): class Plugins2countManager(StaticData):
@ -14,16 +15,9 @@ class Plugins2countManager(StaticData):
""" """
def __init__(self, file: Path): def __init__(self, file: Path):
self.file = file super().__init__(file, False)
super().__init__(None)
self._daily_limiter: Dict[str, DailyNumberLimiter] = {} self._daily_limiter: Dict[str, DailyNumberLimiter] = {}
if file.exists(): self.__load_file()
with open(file, "r", encoding="utf8") as f:
self._data = yaml.load(f)
if "PluginCountLimit" in self._data.keys():
self._data = (
self._data["PluginCountLimit"] if self._data["PluginCountLimit"] else {}
)
def add_count_limit( def add_count_limit(
self, self,
@ -31,64 +25,64 @@ class Plugins2countManager(StaticData):
*, *,
max_count: int = 5, max_count: int = 5,
status: Optional[bool] = True, status: Optional[bool] = True,
limit_type: Optional[str] = "user", limit_type: Literal["user", "group"] = "user",
rst: Optional[str] = None, rst: Optional[str] = None,
**kwargs # 用于接收额外实参
): ):
""" """
添加插件调用 次数 限制 说明:
:param plugin: 插件模块名称 添加插件调用 次数 限制
:param max_count: 最大次数限制 参数:
:param status: 默认开关状态 :param plugin: 插件模块名称
:param limit_type: 限制类型 监听对象以user_id或group_id作为键来限制'user'用户id'group'群id :param max_count: 最大次数限制
:param rst: 回复的话为空则不回复 :param status: 默认开关状态
:param limit_type: 限制类型 监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
:param rst: 回复的话为空则不回复
""" """
max_count = max_count or 5
status = status or True
limit_type = limit_type or "user"
if limit_type not in ["user", "group"]: if limit_type not in ["user", "group"]:
raise ValueError(f"{plugin} 添加count限制错误limit_type 必须为 'user'/'group'") raise ValueError(f"{plugin} 添加count限制错误limit_type 必须为 'user'/'group'")
self._data[plugin] = { self._data[plugin] = PluginCount(max_count=max_count, status=status, limit_type=limit_type, rst=rst)
"max_count": max_count,
"status": status,
"limit_type": limit_type,
"rst": rst,
}
def get_plugin_count_data(self, plugin: str) -> Optional[dict]: def get_plugin_count_data(self, plugin: str) -> Optional[PluginCount]:
""" """
获取插件次数数据 说明:
:param plugin: 模块名 获取插件次数数据
参数:
:param plugin: 模块名
""" """
if self.check_plugin_count_status(plugin): if self.check_plugin_count_status(plugin):
return self._data[plugin] return self._data[plugin]
return None return None
def get_plugin_data(self, plugin: str) -> Optional[dict]: def get_plugin_data(self, plugin: str) -> Optional[PluginCount]:
""" """
获取单个模块限制数据 说明:
:param plugin: 模块名 获取单个模块限制数据
参数:
:param plugin: 模块名
""" """
if self._data.get(plugin) is not None: if self._data.get(plugin) is not None:
return self._data.get(plugin) return self._data.get(plugin)
return None
def check_plugin_count_status(self, plugin: str) -> bool: def check_plugin_count_status(self, plugin: str) -> bool:
""" """
检测插件是否有 次数 限制 说明:
:param plugin: 模块名 检测插件是否有 次数 限制
参数:
:param plugin: 模块名
""" """
return ( return (
plugin in self._data.keys() plugin in self._data.keys()
and self._data[plugin]["status"] and self._data[plugin].status
and self._data[plugin]["max_count"] > 0 and self._data[plugin].max_count > 0
) )
def check(self, plugin: str, id_: int) -> bool: def check(self, plugin: str, id_: int) -> bool:
""" """
检查 count 说明:
:param plugin: 模块名 检查 count
:param id_: 限制 id 参数:
:param plugin: 模块名
:param id_: 限制 id
""" """
if self._daily_limiter.get(plugin): if self._daily_limiter.get(plugin):
return self._daily_limiter[plugin].check(id_) return self._daily_limiter[plugin].check(id_)
@ -96,24 +90,25 @@ class Plugins2countManager(StaticData):
def increase(self, plugin: str, id_: int, num: int = 1): def increase(self, plugin: str, id_: int, num: int = 1):
""" """
增加次数 说明:
:param plugin: 模块名 增加次数
:param id_: cd 限制类型 参数:
:param num: 增加次数 :param plugin: 模块名
:return: :param id_: cd 限制类型
:param num: 增加次数
""" """
if self._daily_limiter.get(plugin): if self._daily_limiter.get(plugin):
self._daily_limiter[plugin].increase(id_, num) self._daily_limiter[plugin].increase(id_, num)
def reload_count_limit(self): def reload_count_limit(self):
""" """
加载 cd 限制器 说明:
:return: 加载 cd 限制器
""" """
for plugin in self._data: for plugin in self._data:
if self.check_plugin_count_status(plugin): if self.check_plugin_count_status(plugin):
self._daily_limiter[plugin] = DailyNumberLimiter( self._daily_limiter[plugin] = DailyNumberLimiter(
self.get_plugin_count_data(plugin)["max_count"] self.get_plugin_count_data(plugin).max_count
) )
logger.info(f"已成功加载 {len(self._daily_limiter)} 个Count限制.") logger.info(f"已成功加载 {len(self._daily_limiter)} 个Count限制.")
@ -121,8 +116,59 @@ class Plugins2countManager(StaticData):
""" """
重载本地数据 重载本地数据
""" """
self.__load_file()
self.reload_count_limit()
def save(self, path: Union[str, Path] = None):
"""
说明:
保存文件
参数:
:param path: 文件路径
"""
path = path or self.file
if isinstance(path, str):
path = Path(path)
if path:
with open(path, "w", encoding="utf8") as f:
yaml.dump(
{"PluginCountLimit": self.dict()},
f,
indent=2,
Dumper=yaml.RoundTripDumper,
allow_unicode=True,
)
_data = yaml.round_trip_load(open(path, encoding="utf8"))
_data["PluginCountLimit"].yaml_set_start_comment(
"""# 命令每日次数限制
# 即 用户/群聊 每日可调用命令的次数 [数据内存存储,重启将会重置]
# 每日调用直到 00:00 刷新
# key模块名称
# max_count: 每日调用上限
# status此限制的开关状态
# limit_type监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
# 示例:'user':用户上限,'group':群聊上限
# rst回复的话可以添加[at][uname][nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(path, "w", encoding="utf8") as wf:
yaml.round_trip_dump(
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
def __load_file(self):
"""
说明:
读取配置文件
"""
self._data: Dict[str, PluginCount] = {}
if self.file.exists(): if self.file.exists():
with open(self.file, "r", encoding="utf8") as f: with open(self.file, "r", encoding="utf8") as f:
self._data: dict = yaml.load(f) temp = _yaml.load(f)
self._data = self._data["PluginCountLimit"] if "PluginCountLimit" in temp.keys():
self.reload_count_limit() for k, v in temp["PluginCountLimit"].items():
self._data[k] = PluginCount.parse_obj(v)

143
utils/manager/plugins2settings_manager.py Executable file → Normal file
View File

@ -1,11 +1,11 @@
from typing import List, Optional, Union, Tuple from typing import List, Optional, Union, Tuple, Dict
from .data_class import StaticData from utils.manager.data_class import StaticData
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML
from ruamel import yaml from ruamel import yaml
from .models import PluginSetting
_yaml = YAML(typ="safe") _yaml = yaml.YAML(typ="safe")
class Plugins2settingsManager(StaticData): class Plugins2settingsManager(StaticData):
@ -14,97 +14,120 @@ class Plugins2settingsManager(StaticData):
""" """
def __init__(self, file: Path): def __init__(self, file: Path):
self.file = file super().__init__(file, False)
super().__init__(None) self.__load_file()
if file.exists():
with open(file, "r", encoding="utf8") as f:
self._data = _yaml.load(f)
if self._data:
if "PluginSettings" in self._data.keys():
self._data = (
self._data["PluginSettings"] if self._data["PluginSettings"] else {}
)
for x in self._data.keys():
if self._data[x].get("cost_gold") is None:
self._data[x]["cost_gold"] = 0
def add_plugin_settings( def add_plugin_settings(
self, self,
plugin: str, plugin: str,
cmd: Optional[List[str]] = None, cmd: Optional[List[str]] = None,
default_status: Optional[bool] = True, default_status: bool = True,
level: Optional[int] = 5, level: int = 5,
limit_superuser: Optional[bool] = False, limit_superuser: bool = False,
plugin_type: Tuple[Union[str, int]] = ("normal",), plugin_type: Tuple[Union[str, int]] = ("normal",),
cost_gold: int = 0, cost_gold: int = 0,
): ):
""" """
添加一个插件设置 说明:
:param plugin: 插件模块名称 添加一个插件设置
:param cmd: 命令 命令别名 参数:
:param default_status: 默认开关状态 :param plugin: 插件模块名称
:param level: 功能权限等级 :param cmd: 命令 命令别名
:param limit_superuser: 功能状态是否限制超级用户 :param default_status: 默认开关状态
:param plugin_type: 插件类型 :param level: 功能权限等级
:param cost_gold: 需要消费的金币 :param limit_superuser: 功能状态是否限制超级用户
:param plugin_type: 插件类型
:param cost_gold: 需要消费的金币
""" """
level = level or 5 self._data[plugin] = PluginSetting(
cmd = cmd or [] cmd=cmd,
cost_gold = cost_gold or 0 level=level,
self._data[plugin] = { default_status=default_status,
"level": level if level is not None else 5, limit_superuser=limit_superuser,
"default_status": default_status if default_status is not None else True, plugin_type=plugin_type,
"limit_superuser": ( cost_gold=cost_gold,
limit_superuser )
if limit_superuser is not None
else False
),
"cmd": cmd,
"plugin_type": list(
plugin_type if plugin_type is not None else ("normal",)
),
"cost_gold": cost_gold,
}
def get_plugin_data(self, module: str) -> dict: def get_plugin_data(self, module: str) -> Optional[PluginSetting]:
""" """
通过模块名获取数据 说明:
:param module: 模块名称 通过模块名获取数据
参数:
:param module: 模块名称
""" """
if self._data.get(module) is not None: return self._data.get(module)
return self._data.get(module)
return {}
def get_plugin_module( def get_plugin_module(
self, cmd: str, is_all: bool = False self, cmd: str, is_all: bool = False
) -> Union[str, List[str]]: ) -> Union[str, List[str]]:
""" """
根据 cmd 获取功能 modules 说明:
:param cmd: 命令 根据 cmd 获取功能 modules
:param is_all: 获取全部包含cmd的模块 参数:
:param cmd: 命令
:param is_all: 获取全部包含cmd的模块
""" """
keys = [] keys = []
for key in self._data.keys(): for key in self._data.keys():
if cmd in self._data[key]["cmd"]: if cmd in self._data[key].cmd:
if is_all: if is_all:
keys.append(key) keys.append(key)
else: else:
return key return key
return keys return keys
def reload(self):
"""
说明:
重载本地数据
"""
self.__load_file()
def save(self, path: Union[str, Path] = None): def save(self, path: Union[str, Path] = None):
"""
说明:
保存文件
参数:
:param path: 文件路径
"""
path = path or self.file path = path or self.file
if isinstance(path, str): if isinstance(path, str):
path = Path(path) path = Path(path)
if path: if path:
with open(path, "w", encoding="utf8") as f: with open(path, "w", encoding="utf8") as f:
yaml.dump({"PluginSettings": self._data}, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True) yaml.dump(
{"PluginSettings": self.dict()},
f,
indent=2,
Dumper=yaml.RoundTripDumper,
allow_unicode=True,
)
_data = yaml.round_trip_load(open(path, encoding="utf8"))
_data["PluginSettings"].yaml_set_start_comment(
"""# 模块与对应命令和对应群权限
# 用于生成帮助图片 和 开关功能
# key模块名称
# level需要的群等级
# default_status加入群时功能的默认开关状态
# limit_superuser: 功能状态是否限制超级用户
# cmd: 关闭[cmd] 都会触发命令 关闭对应功能cmd列表第一个词为统计的功能名称
# plugin_type: 帮助类别 示例:('原神相关',) 或 ('原神相关', 1)1代表帮助命令列向排列否则为横向排列""",
indent=2,
)
with open(path, "w", encoding="utf8") as wf:
yaml.round_trip_dump(
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
def reload(self): def __load_file(self):
""" """
重载本地数据 说明:
读取配置文件
""" """
self._data: Dict[str, PluginSetting] = {}
if self.file.exists(): if self.file.exists():
with open(self.file, "r", encoding="utf8") as f: with open(self.file, "r", encoding="utf8") as f:
self._data: dict = _yaml.load(f) temp = _yaml.load(f)
self._data = self._data["PluginSettings"] if "PluginSettings" in temp.keys():
for k, v in temp["PluginSettings"].items():
self._data[k] = PluginSetting.parse_obj(v)

123
utils/manager/plugins_manager.py Executable file → Normal file
View File

@ -1,7 +1,33 @@
from typing import Optional from typing import Optional, Dict, Callable, Union
from pathlib import Path from pathlib import Path
from .data_class import StaticData from utils.manager.data_class import StaticData
from . import group_manager from utils.manager import group_manager
from .models import Plugin
def init_plugin(func: Callable):
"""
说明:
初始化群数据
参数:
:param func: func
"""
def wrapper(*args, **kwargs):
self = args[0]
module = args[1]
if module not in self._data.keys():
self._data[module] = Plugin(
plugin_name=module,
status=True,
error=False,
block_type=None,
author=None,
version=None,
)
return func(*args, **kwargs)
return wrapper
class PluginsManager(StaticData): class PluginsManager(StaticData):
@ -10,9 +36,10 @@ class PluginsManager(StaticData):
""" """
def __init__(self, file: Path): def __init__(self, file: Path):
self._data: Dict[str, Plugin]
super().__init__(file) super().__init__(file)
if not self._data: for k, v in self._data.items():
self._data = {} self._data[k] = Plugin.parse_obj(v)
def add_plugin_data( def add_plugin_data(
self, self,
@ -26,23 +53,25 @@ class PluginsManager(StaticData):
version: Optional[int] = None, version: Optional[int] = None,
): ):
""" """
添加插件数据 说明:
:param module: 模块名称 添加插件数据
:param plugin_name: 插件名称 参数:
:param status: 插件开关状态 :param module: 模块名称
:param error: 加载状态 :param plugin_name: 插件名称
:param block_type: 限制类型 :param status: 插件开关状态
:param author: 作者 :param error: 加载状态
:param version: 版本 :param block_type: 限制类型
:param author: 作者
:param version: 版本
""" """
self._data[module] = { self._data[module] = Plugin(
"plugin_name": plugin_name, plugin_name=plugin_name,
"status": status, status=status,
"error": error, error=error,
"block_type": block_type, block_type=block_type,
"author": author, author=author,
"version": version, version=version,
} )
def block_plugin( def block_plugin(
self, module: str, group_id: Optional[int] = None, block_type: str = "all" self, module: str, group_id: Optional[int] = None, block_type: str = "all"
@ -67,9 +96,7 @@ class PluginsManager(StaticData):
""" """
self._set_plugin_status(module, "unblock", group_id) self._set_plugin_status(module, "unblock", group_id)
def get_plugin_status( def get_plugin_status(self, module: str, block_type: str = "all") -> bool:
self, module: str, block_type: str = "all"
) -> bool:
""" """
说明: 说明:
获取插件状态 获取插件状态
@ -78,13 +105,12 @@ class PluginsManager(StaticData):
:param block_type: 限制类型 :param block_type: 限制类型
""" """
if module in self._data.keys(): if module in self._data.keys():
if self._data[module]["block_type"] == "all" and block_type == "all": if self._data[module].block_type == "all" and block_type == "all":
return False return False
else: return not self._data[module].block_type == block_type
return not self._data[module]["block_type"] == block_type
return True return True
def get_plugin_block_type(self, module: str) -> str: def get_plugin_block_type(self, module: str) -> Optional[str]:
""" """
说明: 说明:
获取功能限制类型 获取功能限制类型
@ -92,18 +118,19 @@ class PluginsManager(StaticData):
:param module: 模块名称 :param module: 模块名称
""" """
if module in self._data.keys(): if module in self._data.keys():
return self._data[module]["block_type"] return self._data[module].block_type
return ""
@init_plugin
def get_plugin_error_status(self, module: str) -> bool: def get_plugin_error_status(self, module: str) -> bool:
""" """
插件是否成功加载 说明:
:param module: 模块名称 插件是否成功加载
参数:
:param module: 模块名称
""" """
if module not in self._data.keys(): return self._data[module].error
self.init_plugin(module)
return self._data[module]["error"]
@init_plugin
def _set_plugin_status( def _set_plugin_status(
self, self,
module: str, module: str,
@ -120,7 +147,6 @@ class PluginsManager(StaticData):
:param group_id: 群组 :param group_id: 群组
:param block_type: 限制类型 :param block_type: 限制类型
""" """
group_id = str(group_id) if group_id else group_id
if module: if module:
if group_id: if group_id:
if status == "block": if status == "block":
@ -128,28 +154,11 @@ class PluginsManager(StaticData):
else: else:
group_manager.unblock_plugin(f"{module}:super", int(group_id)) group_manager.unblock_plugin(f"{module}:super", int(group_id))
else: else:
if module not in self._data.keys():
self.init_plugin(module)
if status == "block": if status == "block":
self._data[module]["status"] = False self._data[module].status = False
self._data[module]["block_type"] = block_type self._data[module].block_type = block_type
else: else:
if module in self._data.keys(): if module in self._data.keys():
self._data[module]["status"] = True self._data[module].status = True
self._data[module]["block_type"] = None self._data[module].block_type = None
self.save() self.save()
def init_plugin(self, module: str):
"""
初始化插件数据
:param module: 模块名称
"""
if module not in self._data.keys():
self._data[module] = {
"plugin_name": module,
"status": True,
"error": False,
"block_type": None,
"author": None,
"version": None,
}

542
utils/manager/requests_manager.py Executable file → Normal file
View File

@ -1,271 +1,271 @@
from utils.manager.data_class import StaticData from utils.manager.data_class import StaticData
from nonebot.adapters.onebot.v11 import Bot, ActionFailed from nonebot.adapters.onebot.v11 import Bot, ActionFailed
from services.log import logger from services.log import logger
from typing import Optional, Literal from typing import Optional
from utils.image_utils import BuildImage from utils.image_utils import BuildImage
from utils.utils import get_user_avatar from utils.utils import get_user_avatar
from pathlib import Path from pathlib import Path
from io import BytesIO from io import BytesIO
class RequestManager(StaticData): class RequestManager(StaticData):
""" """
好友请求/邀请请求 管理 好友请求/邀请请求 管理
""" """
def __init__(self, file: Optional[Path]): def __init__(self, file: Optional[Path]):
super().__init__(file) super().__init__(file)
if not self._data: if not self._data:
self._data = {"private": {}, "group": {}} self._data = {"private": {}, "group": {}}
def add_request( def add_request(
self, self,
id_: int, id_: int,
type_: str, type_: str,
flag: str, flag: str,
*, *,
nickname: Optional[str] = None, nickname: Optional[str] = None,
level: Optional[int] = None, level: Optional[int] = None,
sex: Optional[str] = None, sex: Optional[str] = None,
age: Optional[str] = None, age: Optional[str] = None,
from_: Optional[str] = "", from_: Optional[str] = "",
comment: Optional[str] = None, comment: Optional[str] = None,
invite_group: Optional[int] = None, invite_group: Optional[int] = None,
group_name: Optional[str] = None, group_name: Optional[str] = None,
): ):
""" """
添加一个请求 添加一个请求
:param id_: id用户id或群id :param id_: id用户id或群id
:param type_: 类型private group :param type_: 类型private group
:param flag: event.flag :param flag: event.flag
:param nickname: 用户昵称 :param nickname: 用户昵称
:param level: 等级 :param level: 等级
:param sex: 性别 :param sex: 性别
:param age: 年龄 :param age: 年龄
:param from_: 请求来自 :param from_: 请求来自
:param comment: 附加消息 :param comment: 附加消息
:param invite_group: 邀请群聊 :param invite_group: 邀请群聊
:param group_name: 群聊名称 :param group_name: 群聊名称
""" """
self._data[type_][str(len(self._data[type_].keys()))] = { self._data[type_][str(len(self._data[type_].keys()))] = {
"id": id_, "id": id_,
"flag": flag, "flag": flag,
"nickname": nickname, "nickname": nickname,
"level": level, "level": level,
"sex": sex, "sex": sex,
"age": age, "age": age,
"from": from_, "from": from_,
"comment": comment, "comment": comment,
"invite_group": invite_group, "invite_group": invite_group,
"group_name": group_name, "group_name": group_name,
} }
self.save() self.save()
def remove_request(self, type_: str, id_: int): def remove_request(self, type_: str, id_: int):
""" """
删除一个请求数据 删除一个请求数据
:param type_: 类型 :param type_: 类型
:param id_: iduser_id group_id :param id_: iduser_id group_id
""" """
for x in self._data[type_].keys(): for x in self._data[type_].keys():
if self._data[type_][x].get("id") == id_: if self._data[type_][x].get("id") == id_:
del self._data[type_][x] del self._data[type_][x]
break break
self.save() self.save()
def get_group_id(self, id_: int) -> Optional[int]: def get_group_id(self, id_: int) -> Optional[int]:
""" """
通过id获取群号 通过id获取群号
:param id_: id :param id_: id
""" """
data = self._data["group"].get(str(id_)) data = self._data["group"].get(str(id_))
if data: if data:
return data["invite_group"] return data["invite_group"]
return None return None
async def approve(self, bot: Bot, id_: int, type_: str) -> int: async def approve(self, bot: Bot, id_: int, type_: str) -> int:
""" """
同意请求 同意请求
:param bot: Bot :param bot: Bot
:param id_: id :param id_: id
:param type_: 类型private group :param type_: 类型private group
""" """
return await self._set_add_request(bot, id_, type_, True) return await self._set_add_request(bot, id_, type_, True)
async def refused(self, bot: Bot, id_: int, type_: str) -> Optional[int]: async def refused(self, bot: Bot, id_: int, type_: str) -> Optional[int]:
""" """
拒绝请求 拒绝请求
:param bot: Bot :param bot: Bot
:param id_: id :param id_: id
:param type_: 类型private group :param type_: 类型private group
""" """
return await self._set_add_request(bot, id_, type_, False) return await self._set_add_request(bot, id_, type_, False)
def clear(self, type_: Optional[str] = None): # type_: Optional[Literal["group", "private"]] = None def clear(self, type_: Optional[str] = None): # type_: Optional[Literal["group", "private"]] = None
""" """
清空所有请求信息无视请求 清空所有请求信息无视请求
:param type_: 类型 :param type_: 类型
""" """
if type_: if type_:
self._data[type_] = {} self._data[type_] = {}
else: else:
self._data = {"private": {}, "group": {}} self._data = {"private": {}, "group": {}}
self.save() self.save()
def delete_request(self, id_: int, type_: str): # type_: Literal["group", "private"] def delete_request(self, id_: int, type_: str): # type_: Literal["group", "private"]
""" """
删除请求 删除请求
:param id_: id :param id_: id
:param type_: 类型 :param type_: 类型
""" """
id_ = str(id_) id_ = str(id_)
if self._data[type_].get(id_): if self._data[type_].get(id_):
del self._data[type_][id_] del self._data[type_][id_]
self.save() self.save()
def set_group_name(self, group_name: str, group_id: int): def set_group_name(self, group_name: str, group_id: int):
""" """
设置群聊名称 设置群聊名称
:param group_name: 名称 :param group_name: 名称
:param group_id: id :param group_id: id
""" """
for id_ in self._data["group"].keys(): for id_ in self._data["group"].keys():
if self._data["group"][id_]["invite_group"] == group_id: if self._data["group"][id_]["invite_group"] == group_id:
self._data["group"][id_]["group_name"] = group_name self._data["group"][id_]["group_name"] = group_name
break break
self.save() self.save()
async def show(self, type_: str) -> Optional[str]: async def show(self, type_: str) -> Optional[str]:
""" """
请求可视化 请求可视化
""" """
data = self._data[type_] data = self._data[type_]
if not data: if not data:
return None return None
img_list = [] img_list = []
id_list = list(data.keys()) id_list = list(data.keys())
id_list.reverse() id_list.reverse()
for id_ in id_list: for id_ in id_list:
age = data[id_]["age"] age = data[id_]["age"]
nickname = data[id_]["nickname"] nickname = data[id_]["nickname"]
comment = data[id_]["comment"] if type_ == "private" else "" comment = data[id_]["comment"] if type_ == "private" else ""
from_ = data[id_]["from"] from_ = data[id_]["from"]
sex = data[id_]["sex"] sex = data[id_]["sex"]
ava = BuildImage( ava = BuildImage(
80, 80, background=BytesIO(await get_user_avatar(data[id_]["id"])) 80, 80, background=BytesIO(await get_user_avatar(data[id_]["id"]))
) )
ava.circle() ava.circle()
age_bk = BuildImage( age_bk = BuildImage(
len(str(age)) * 6 + 6, len(str(age)) * 6 + 6,
15, 15,
color="#04CAF7" if sex == "male" else "#F983C1", color="#04CAF7" if sex == "male" else "#F983C1",
) )
age_bk.text((3, 1), f"{age}", fill=(255, 255, 255)) age_bk.text((3, 1), f"{age}", fill=(255, 255, 255))
x = BuildImage( x = BuildImage(
90, 32, font_size=15, color="#EEEFF4", font="HYWenHei-85W.ttf" 90, 32, font_size=15, color="#EEEFF4", font="HYWenHei-85W.ttf"
) )
x.text((0, 0), "同意/拒绝", center_type="center") x.text((0, 0), "同意/拒绝", center_type="center")
x.circle_corner(10) x.circle_corner(10)
A = BuildImage(500, 100, font_size=24, font="msyh.ttf") A = BuildImage(500, 100, font_size=24, font="msyh.ttf")
A.paste(ava, (15, 0), alpha=True, center_type="by_height") A.paste(ava, (15, 0), alpha=True, center_type="by_height")
A.text((120, 15), nickname) A.text((120, 15), nickname)
A.paste(age_bk, (120, 50), True) A.paste(age_bk, (120, 50), True)
A.paste( A.paste(
BuildImage( BuildImage(
200, 200,
0, 0,
font_size=12, font_size=12,
plain_text=f"对方留言:{comment}", plain_text=f"对方留言:{comment}",
font_color=(140, 140, 143), font_color=(140, 140, 143),
), ),
(120 + age_bk.w + 10, 49), (120 + age_bk.w + 10, 49),
True, True,
) )
if type_ == "private": if type_ == "private":
A.paste( A.paste(
BuildImage( BuildImage(
200, 200,
0, 0,
font_size=12, font_size=12,
plain_text=f"来源:{from_}", plain_text=f"来源:{from_}",
font_color=(140, 140, 143), font_color=(140, 140, 143),
), ),
(120, 70), (120, 70),
True, True,
) )
else: else:
A.paste( A.paste(
BuildImage( BuildImage(
200, 200,
0, 0,
font_size=12, font_size=12,
plain_text=f"邀请你加入:{data[id_]['group_name']}({data[id_]['invite_group']})", plain_text=f"邀请你加入:{data[id_]['group_name']}({data[id_]['invite_group']})",
font_color=(140, 140, 143), font_color=(140, 140, 143),
), ),
(120, 70), (120, 70),
True, True,
) )
A.paste(x, (380, 35), True) A.paste(x, (380, 35), True)
A.paste( A.paste(
BuildImage( BuildImage(
0, 0,
0, 0,
plain_text=f"id{id_}", plain_text=f"id{id_}",
font_size=13, font_size=13,
font_color=(140, 140, 143), font_color=(140, 140, 143),
), ),
(400, 10), (400, 10),
True, True,
) )
img_list.append(A) img_list.append(A)
A = BuildImage(500, len(img_list) * 100, 500, 100) A = BuildImage(500, len(img_list) * 100, 500, 100)
for img in img_list: for img in img_list:
A.paste(img) A.paste(img)
bk = BuildImage(A.w, A.h + 50, color="#F8F9FB", font_size=20) bk = BuildImage(A.w, A.h + 50, color="#F8F9FB", font_size=20)
bk.paste(A, (0, 50)) bk.paste(A, (0, 50))
bk.text( bk.text(
(15, 13), "好友请求" if type_ == "private" else "群聊请求", fill=(140, 140, 143) (15, 13), "好友请求" if type_ == "private" else "群聊请求", fill=(140, 140, 143)
) )
return bk.pic2bs4() return bk.pic2bs4()
async def _set_add_request( async def _set_add_request(
self, bot: Bot, id_: int, type_: str, approve: bool self, bot: Bot, id_: int, type_: str, approve: bool
) -> int: ) -> int:
""" """
处理请求 处理请求
:param bot: Bot :param bot: Bot
:param id_: id :param id_: id
:param type_: 类型private group :param type_: 类型private group
:param approve: 是否同意 :param approve: 是否同意
""" """
id_ = str(id_) id_ = str(id_)
if id_ in self._data[type_].keys(): if id_ in self._data[type_].keys():
try: try:
if type_ == "private": if type_ == "private":
await bot.set_friend_add_request( await bot.set_friend_add_request(
flag=self._data[type_][id_]["flag"], approve=approve flag=self._data[type_][id_]["flag"], approve=approve
) )
rid = self._data[type_][id_]["id"] rid = self._data[type_][id_]["id"]
else: else:
await bot.set_group_add_request( await bot.set_group_add_request(
flag=self._data[type_][id_]["flag"], flag=self._data[type_][id_]["flag"],
sub_type="invite", sub_type="invite",
approve=approve, approve=approve,
) )
rid = self._data[type_][id_]["invite_group"] rid = self._data[type_][id_]["invite_group"]
except ActionFailed: except ActionFailed:
logger.info( logger.info(
f"同意{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})" f"同意{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})"
f"{'好友' if type_ == 'private' else '入群'}请求失败了..." f"{'好友' if type_ == 'private' else '入群'}请求失败了..."
) )
return 1 # flag失效 return 1 # flag失效
else: else:
logger.info( logger.info(
f"{'同意' if approve else '拒绝'}{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})" f"{'同意' if approve else '拒绝'}{self._data[type_][id_]['nickname']}({self._data[type_][id_]['id']})"
f"{'好友' if type_ == 'private' else '入群'}请求..." f"{'好友' if type_ == 'private' else '入群'}请求..."
) )
del self._data[type_][id_] del self._data[type_][id_]
self.save() self.save()
return rid return rid
return 2 # 未找到id return 2 # 未找到id

2
utils/manager/resources_manager.py Executable file → Normal file
View File

@ -1,7 +1,7 @@
from typing import Union, List, Optional from typing import Union, List, Optional
from configs.path_config import IMAGE_PATH, DATA_PATH, RECORD_PATH, TEXT_PATH, FONT_PATH, LOG_PATH from configs.path_config import IMAGE_PATH, DATA_PATH, RECORD_PATH, TEXT_PATH, FONT_PATH, LOG_PATH
from .data_class import StaticData from utils.manager.data_class import StaticData
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML from ruamel.yaml import YAML
from services.log import logger from services.log import logger

0
utils/manager/withdraw_message_manager.py Executable file → Normal file
View File

View File

@ -450,4 +450,4 @@ def change_img_md5(path_file: Union[str, Path]) -> bool:
return True return True
except Exception as e: except Exception as e:
logger.warning(f"改变图片MD5发生错误 {type(e)}{e} Path{path_file}") logger.warning(f"改变图片MD5发生错误 {type(e)}{e} Path{path_file}")
return False return False