From 1046815d37b6ae135d3de7e0e52db34eb5ebe28f Mon Sep 17 00:00:00 2001 From: HibiKier <775757368@qq.com> Date: Sun, 19 Mar 2023 21:05:34 +0800 Subject: [PATCH] FIX BUG --- README.md | 6 + .../admin_bot_manage/_data_source.py | 167 +++++---- .../admin_bot_manage/admin_config.py | 23 +- .../custom_welcome_message.py | 14 +- basic_plugins/admin_bot_manage/rule.py | 8 +- basic_plugins/admin_bot_manage/switch_rule.py | 57 +-- basic_plugins/admin_bot_manage/timing_task.py | 46 ++- .../update_group_member_info.py | 21 +- basic_plugins/admin_help/data_source.py | 17 +- basic_plugins/apscheduler/__init__.py | 67 ++-- basic_plugins/broadcast/__init__.py | 15 +- basic_plugins/chat_history/_rule.py | 5 +- basic_plugins/group_handle/__init__.py | 57 +-- basic_plugins/help/__init__.py | 42 ++- basic_plugins/help/_data_source.py | 67 ++-- basic_plugins/help/_utils.py | 18 +- basic_plugins/hooks/_utils.py | 338 ++++++++++-------- basic_plugins/hooks/ban_hook.py | 71 ++-- basic_plugins/hooks/chkdsk_hook.py | 40 ++- basic_plugins/hooks/task_hook.py | 22 +- basic_plugins/hooks/withdraw_message_hook.py | 10 +- basic_plugins/invite_manager/__init__.py | 2 +- basic_plugins/plugin_shop/data_source.py | 11 +- basic_plugins/shop/my_props/__init__.py | 2 +- basic_plugins/shop/shop_handle/__init__.py | 14 +- basic_plugins/shop/shop_handle/data_source.py | 4 +- basic_plugins/shop/use/__init__.py | 6 +- basic_plugins/super_cmd/manager_group.py | 53 ++- basic_plugins/super_help/data_source.py | 13 +- basic_plugins/update_info.py | 2 +- models/group_member_info.py | 3 +- plugins/open_cases/build_image.py | 41 ++- plugins/open_cases/models/buff_skin.py | 1 + plugins/open_cases/utils.py | 21 +- plugins/sign_in/utils.py | 2 +- resources/image/_icon/reload_white.png | Bin 0 -> 4227 bytes 36 files changed, 704 insertions(+), 582 deletions(-) create mode 100644 resources/image/_icon/reload_white.png diff --git a/README.md b/README.md index dfb95c15..225bab7d 100644 --- a/README.md +++ b/README.md @@ -331,6 +331,12 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能 ## 更新 +### 2023/3/19 + +* 优化代码 +* 查看武器箱及皮肤添加更新次数 +* 修复添加群认证会检测群聊是否存在 + ### 2023/3/18 * 修复色图重复发送相同图片 diff --git a/basic_plugins/admin_bot_manage/_data_source.py b/basic_plugins/admin_bot_manage/_data_source.py index 61edb9bf..fdd9d366 100644 --- a/basic_plugins/admin_bot_manage/_data_source.py +++ b/basic_plugins/admin_bot_manage/_data_source.py @@ -1,12 +1,12 @@ import asyncio import os import time -from datetime import datetime +from datetime import datetime, timedelta, timezone from pathlib import Path -from typing import List +from typing import List, Union import ujson as json -from nonebot.adapters.onebot.v11.message import MessageSegment +from nonebot.adapters.onebot.v11 import Bot, Message, MessageSegment from configs.config import Config from configs.path_config import DATA_PATH, IMAGE_PATH @@ -17,7 +17,7 @@ from utils.http_utils import AsyncHttpx from utils.image_utils import BuildImage from utils.manager import group_manager, plugins2settings_manager, plugins_manager from utils.message_builder import image -from utils.utils import get_bot, get_matchers +from utils.utils import get_matchers custom_welcome_msg_json = ( Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json" @@ -67,7 +67,7 @@ async def group_current_status(group_id: int) -> str: async def custom_group_welcome( msg: str, img_list: List[str], user_id: int, group_id: int -) -> str: +) -> Union[str, Message]: """ 说明: 替换群欢迎消息 @@ -80,8 +80,9 @@ async def custom_group_welcome( img_result = "" result = "" img = img_list[0] if img_list else "" - if (DATA_PATH / f"custom_welcome_msg/{group_id}.jpg").exists(): - (DATA_PATH / f"custom_welcome_msg/{group_id}.jpg").unlink() + msg_image = DATA_PATH / "custom_welcome_msg" / f"{group_id}.jpg" + if msg_image.exists(): + msg_image.unlink() data = {} if not custom_welcome_msg_json.exists(): custom_welcome_msg_json.parent.mkdir(parents=True, exist_ok=True) @@ -96,17 +97,15 @@ async def custom_group_welcome( json.dump( data, open(custom_welcome_msg_json, "w"), indent=4, ensure_ascii=False ) - logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息 {msg}") + logger.info(f"更换群欢迎消息 {msg}", "更换群欢迎信息", user_id, group_id) result += msg if img: - await AsyncHttpx.download_file( - img, DATA_PATH / "custom_welcome_msg" / f"{group_id}.jpg" - ) - img_result = image(DATA_PATH / "custom_welcome_msg" / f"{group_id}.jpg") - logger.info(f"USER {user_id} GROUP {group_id} 更换群欢迎消息图片") + await AsyncHttpx.download_file(img, msg_image) + img_result = image(msg_image) + logger.info(f"更换群欢迎消息图片", "更换群欢迎信息", user_id, group_id) except Exception as e: - logger.error(f"GROUP {group_id} 替换群消息失败 e:{e}") - return "替换群消息失败.." + logger.error(f"替换群消息失败", "更换群欢迎信息", user_id, group_id, e=e) + return "替换群消息失败..." return f"替换群欢迎消息成功:\n{result}" + img_result @@ -255,11 +254,8 @@ def _get_plugin_status() -> MessageSegment: """ rst = "\t功能\n" flag_str = "状态".rjust(4) + "\n" - tmp_name = [] - for matcher in get_matchers(): - if matcher.plugin_name not in tmp_name: - tmp_name.append(matcher.plugin_name) - module = matcher.plugin_name + for matcher in get_matchers(True): + if module := matcher.plugin_name: flag = plugins_manager.get_plugin_block_type(module) flag = flag.upper() + " CLOSE" if flag else "OPEN" try: @@ -288,7 +284,9 @@ def _get_plugin_status() -> MessageSegment: return image(b64=A.pic2bs4()) -async def update_member_info(group_id: int, remind_superuser: bool = False) -> bool: +async def update_member_info( + bot: Bot, group_id: int, remind_superuser: bool = False +) -> bool: """ 说明: 更新群成员信息 @@ -296,76 +294,77 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b :param group_id: 群号 :param remind_superuser: 失败信息提醒超级用户 """ - bot = get_bot() _group_user_list = await bot.get_group_member_list(group_id=group_id) _error_member_list = [] _exist_member_list = [] # try: - for user_info in _group_user_list: - nickname = user_info["card"] or user_info["nickname"] - # 更新权限 - if user_info["role"] in [ - "owner", - "admin", - ] and not await LevelUser.is_group_flag(user_info["user_id"], group_id): - await LevelUser.set_level( - user_info["user_id"], - user_info["group_id"], - Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"), - ) - if str(user_info["user_id"]) in bot.config.superusers: - await LevelUser.set_level(user_info["user_id"], user_info["group_id"], 9) - user = await GroupInfoUser.get_or_none( - user_qq=user_info["user_id"], group_id=user_info["group_id"] - ) - if user: - if user.user_name != nickname: - user.user_name = nickname - await user.save(update_fields=["user_name"]) - logger.info( - f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新群昵称成功" + admin_default_auth = Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH") + if admin_default_auth is not None: + for user_info in _group_user_list: + nickname = user_info["card"] or user_info["nickname"] + # 更新权限 + if user_info["role"] in [ + "owner", + "admin", + ] and not await LevelUser.is_group_flag(user_info["user_id"], group_id): + await LevelUser.set_level( + user_info["user_id"], + user_info["group_id"], + admin_default_auth, ) + if str(user_info["user_id"]) in bot.config.superusers: + await LevelUser.set_level( + user_info["user_id"], user_info["group_id"], 9 + ) + user = await GroupInfoUser.get_or_none( + user_qq=user_info["user_id"], group_id=user_info["group_id"] + ) + if user: + if user.user_name != nickname: + user.user_name = nickname + await user.save(update_fields=["user_name"]) + logger.debug( + f"更新群昵称成功", + "更新群组成员信息", + user_info["user_id"], + user_info["group_id"], + ) + _exist_member_list.append(int(user_info["user_id"])) + continue + join_time = datetime.strptime( + time.strftime( + "%Y-%m-%d %H:%M:%S", time.localtime(user_info["join_time"]) + ), + "%Y-%m-%d %H:%M:%S", + ) + await GroupInfoUser.update_or_create( + user_qq=user_info["user_id"], + group_id=user_info["group_id"], + defaults={ + "user_name": nickname, + "user_join_time": join_time.replace( + tzinfo=timezone(timedelta(hours=8)) + ), + }, + ) _exist_member_list.append(int(user_info["user_id"])) - continue - join_time = datetime.strptime( - time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(user_info["join_time"])), - "%Y-%m-%d %H:%M:%S", - ) - user, _ = await GroupInfoUser.get_or_create( - user_qq=user_info["user_id"], - group_id=user_info["group_id"], - defaults={ - "user_name": nickname, - }, - ) - # await GroupInfoUser.update_or_create( - # user_qq=user_info["user_id"], - # group_id=user_info["group_id"], - # defaults={ - # "user_name": nickname, - # # "user_join_time": datetime.now().replace(tzinfo=None), - # }, - # ) - user.user_join_time = join_time - await user.save() - _exist_member_list.append(int(user_info["user_id"])) - logger.info("更新成功", "更新成员信息", user_info["user_id"], user_info["group_id"]) - _del_member_list = list( - set(_exist_member_list).difference( - set(await GroupInfoUser.get_group_member_id_list(group_id)) - ) - ) - if _del_member_list: - for del_user in _del_member_list: - await GroupInfoUser.filter(user_qq=del_user, group_id=group_id).delete() - logger.info(f"退群用户{del_user} 所属{group_id} 已删除") - if _error_member_list and remind_superuser: - result = "" - for error_user in _error_member_list: - result += error_user - await bot.send_private_msg( - user_id=int(list(bot.config.superusers)[0]), message=result[:-1] + logger.debug("更新成功", "更新成员信息", user_info["user_id"], user_info["group_id"]) + _del_member_list = list( + set(_exist_member_list).difference( + set(await GroupInfoUser.get_group_member_id_list(group_id)) + ) ) + if _del_member_list: + for del_user in _del_member_list: + await GroupInfoUser.filter(user_qq=del_user, group_id=group_id).delete() + logger.info(f"删除已退群用户", "更新群组成员信息", del_user, group_id) + if _error_member_list and remind_superuser: + result = "" + for error_user in _error_member_list: + result += error_user + await bot.send_private_msg( + user_id=int(list(bot.config.superusers)[0]), message=result[:-1] + ) return True diff --git a/basic_plugins/admin_bot_manage/admin_config.py b/basic_plugins/admin_bot_manage/admin_config.py index 72f685df..45957035 100755 --- a/basic_plugins/admin_bot_manage/admin_config.py +++ b/basic_plugins/admin_bot_manage/admin_config.py @@ -23,15 +23,20 @@ async def _(event: GroupAdminNoticeEvent): else: nickname = event.user_id if event.sub_type == "set": - await LevelUser.set_level( - event.user_id, - event.group_id, - Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"), - ) - logger.info( - f"为新晋管理员 {nickname}({event.user_id}) " - f"添加权限等级:{Config.get_config('admin_bot_manage', 'ADMIN_DEFAULT_AUTH')}" - ) + admin_default_auth = Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH") + if admin_default_auth is not None: + await LevelUser.set_level( + event.user_id, + event.group_id, + admin_default_auth, + ) + logger.info( + f"为新晋管理员 {nickname}({event.user_id}) " f"添加权限等级:{admin_default_auth}" + ) + else: + logger.warning( + f"配置项 MODULE: [admin_bot_manage] | KEY: [ADMIN_DEFAULT_AUTH] 为空" + ) elif event.sub_type == "unset": await LevelUser.delete_level(event.user_id, event.group_id) logger.info(f"将非管理员 {nickname}({event.user_id}) 取消权限等级") diff --git a/basic_plugins/admin_bot_manage/custom_welcome_message.py b/basic_plugins/admin_bot_manage/custom_welcome_message.py index dd1b1594..9f175226 100755 --- a/basic_plugins/admin_bot_manage/custom_welcome_message.py +++ b/basic_plugins/admin_bot_manage/custom_welcome_message.py @@ -1,12 +1,13 @@ from typing import List -from configs.config import Config from nonebot import on_command from nonebot.adapters.onebot.v11 import GroupMessageEvent, Message from nonebot.adapters.onebot.v11.permission import GROUP from nonebot.params import CommandArg + +from configs.config import Config from services.log import logger -from utils.depends import ImageList +from utils.depends import ImageList, OneCommand from ._data_source import custom_group_welcome @@ -40,7 +41,10 @@ custom_welcome = on_command( @custom_welcome.handle() async def _( - event: GroupMessageEvent, arg: Message = CommandArg(), img: List[str] = ImageList() + event: GroupMessageEvent, + cmd: str = OneCommand(), + arg: Message = CommandArg(), + img: List[str] = ImageList(), ): msg = arg.extract_plain_text().strip() if not msg and not img: @@ -52,5 +56,7 @@ async def _( ) logger.info(f"USER {event.user_id} GROUP {event.group_id} 自定义群欢迎消息:{msg}") except Exception as e: - logger.error(f"自定义进群欢迎消息发生错误 {type(e)}:{e}") + logger.error( + f"自定义进群欢迎消息发生错误", cmd, event.user_id, getattr(event, "group_id", None), e=e + ) await custom_welcome.send("发生了一些未知错误...") diff --git a/basic_plugins/admin_bot_manage/rule.py b/basic_plugins/admin_bot_manage/rule.py index e53cf6ae..a0e54efe 100755 --- a/basic_plugins/admin_bot_manage/rule.py +++ b/basic_plugins/admin_bot_manage/rule.py @@ -1,8 +1,10 @@ +import time + from nonebot.adapters.onebot.v11 import Event + +from services.log import logger from utils.manager import group_manager, plugins2settings_manager from utils.utils import get_message_text -from services.log import logger -import time cmd = [] @@ -49,5 +51,5 @@ def switch_rule(event: Event) -> bool: msg = msg[0] if msg else "" return msg in cmd except Exception as e: - logger.error(f"检测是否为功能开关命令发生错误 {type(e)}: {e}") + logger.error(f"检测是否为功能开关命令发生错误", e=e) return False diff --git a/basic_plugins/admin_bot_manage/switch_rule.py b/basic_plugins/admin_bot_manage/switch_rule.py index b909af25..70a50b8b 100755 --- a/basic_plugins/admin_bot_manage/switch_rule.py +++ b/basic_plugins/admin_bot_manage/switch_rule.py @@ -1,23 +1,32 @@ -from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, MessageEvent, GROUP, PrivateMessageEvent -from nonebot import on_command, on_message, on_regex -from nonebot.params import RegexGroup +from typing import Any, Tuple +from nonebot import on_command, on_message, on_regex +from nonebot.adapters.onebot.v11 import ( + GROUP, + Bot, + GroupMessageEvent, + Message, + MessageEvent, + PrivateMessageEvent, +) +from nonebot.params import RegexGroup +from nonebot.permission import SUPERUSER + +from configs.config import NICKNAME, Config +from services.log import logger from utils.message_builder import image +from utils.utils import get_message_text, is_number + from ._data_source import ( + change_global_task_status, change_group_switch, - set_plugin_status, get_plugin_status, group_current_status, - set_group_bot_status, change_global_task_status + set_group_bot_status, + set_plugin_status, ) -from services.log import logger -from configs.config import NICKNAME, Config -from utils.utils import get_message_text, is_number -from nonebot.permission import SUPERUSER -from typing import Tuple, Any from .rule import switch_rule - __zx_plugin_name__ = "群功能开关 [Admin]" __plugin_usage__ = """ @@ -55,7 +64,7 @@ __plugin_version__ = 0.1 __plugin_author__ = "HibiKier" __plugin_settings__ = { "admin_level": Config.get_config("admin_bot_manage", "CHANGE_GROUP_SWITCH_LEVEL"), - "cmd": ["开启功能", "关闭功能", "开关"] + "cmd": ["开启功能", "关闭功能", "开关"], } switch_rule_matcher = on_message(rule=switch_rule, priority=4, block=True) @@ -68,21 +77,27 @@ group_status = on_regex("^(休息吧|醒来)$", permission=GROUP, priority=5, bl @switch_rule_matcher.handle() -async def _(bot: Bot, event: MessageEvent): - _cmd = get_message_text(event.json()).split()[0] +async def _( + bot: Bot, + event: MessageEvent, +): + msg = get_message_text(event.message).strip() + msg_split = msg.split() + _cmd = msg_split[0] if isinstance(event, GroupMessageEvent): await switch_rule_matcher.send(await change_group_switch(_cmd, event.group_id)) - logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用群功能管理命令 {_cmd}") + logger.info(f"使用群功能管理命令 {_cmd}", "功能管理", event.user_id, event.group_id) else: if str(event.user_id) in bot.config.superusers: - block_type = " ".join(get_message_text(event.json()).split()[1:]) + block_type = " ".join(msg_split[1:]) block_type = block_type if block_type else "a" - if ("关闭被动" in _cmd or "开启被动" in _cmd) and isinstance(event, PrivateMessageEvent): + if ("关闭被动" in _cmd or "开启被动" in _cmd) and isinstance( + event, PrivateMessageEvent + ): await switch_rule_matcher.send(change_global_task_status(_cmd)) elif is_number(block_type): if not int(block_type) in [ - g["group_id"] - for g in await bot.get_group_list() + g["group_id"] for g in await bot.get_group_list() ]: await switch_rule_matcher.finish(f"{NICKNAME}未加入群聊:{block_type}") await change_group_switch(_cmd, int(block_type), True) @@ -105,7 +120,7 @@ async def _(bot: Bot, event: MessageEvent): await switch_rule_matcher.send(f"已在群聊中{_cmd[:2]}功能:{_cmd[2:]}") else: await switch_rule_matcher.finish("格式错误:关闭[功能] [group]/[p/g]") - logger.info(f"USER {event.user_id} 使用功能管理命令 {_cmd} | {block_type}") + logger.info(f"使用功能管理命令 {_cmd} | {block_type}", f"{_cmd}", event.user_id) @plugins_status.handle() @@ -126,4 +141,4 @@ async def _(event: GroupMessageEvent, reg_group: Tuple[Any, ...] = RegexGroup()) else: msg = set_group_bot_status(event.group_id, True) await group_status.send(msg) - logger.info(f"USER {event.user_id} GROUP {event.group_id} 使用总开关命令:{cmd}") + logger.info(f"使用总开关命令: {cmd}", cmd, event.user_id, event.group_id) diff --git a/basic_plugins/admin_bot_manage/timing_task.py b/basic_plugins/admin_bot_manage/timing_task.py index 198eef5e..fcae1e74 100755 --- a/basic_plugins/admin_bot_manage/timing_task.py +++ b/basic_plugins/admin_bot_manage/timing_task.py @@ -1,8 +1,7 @@ -from asyncpg.exceptions import ConnectionDoesNotExistError, UndefinedColumnError +from nonebot import get_bots -from models.group_info import GroupInfo from services.log import logger -from utils.utils import get_bot, scheduler +from utils.utils import scheduler from ._data_source import update_member_info @@ -13,6 +12,23 @@ __plugin_version__ = 0.1 __plugin_author__ = "HibiKier" +async def update(): + bot_list = get_bots() + if bot_list: + used_group = [] + for key in bot_list: + bot = bot_list[key] + gl = await bot.get_group_list() + gl = [g["group_id"] for g in gl if g["group_id"] not in used_group] + for g in gl: + used_group.append(g) + try: + await update_member_info(bot, g) # type: ignore + logger.debug(f"更新群组成员信息成功", "自动更新群组成员信息", group_id=g) + except Exception as e: + logger.error(f"更新群组成员信息错误", "自动更新群组成员信息", group_id=g, e=e) + + # 自动更新群员信息 @scheduler.scheduled_job( "cron", @@ -20,16 +36,7 @@ __plugin_author__ = "HibiKier" minute=1, ) async def _(): - bot = get_bot() - if bot: - gl = await bot.get_group_list() - gl = [g["group_id"] for g in gl] - for g in gl: - try: - await update_member_info(g) - logger.info(f"更新群组 g:{g} 成功") - except Exception as e: - logger.error(f"更新群组错误 g:{g} e:{e}") + await update() # 快速更新群员信息以及管理员权限 @@ -38,15 +45,4 @@ async def _(): minutes=5, ) async def _(): - try: - bot = get_bot() - if bot: - gl = await bot.get_group_list() - gl = [g["group_id"] for g in gl] - all_group = [x.group_id for x in await GroupInfo.all()] - for g in gl: - if g not in all_group: - await update_member_info(g, False) - logger.info(f"快速更新群信息以及权限:{g}") - except (IndexError, ConnectionDoesNotExistError, UndefinedColumnError): - pass + await update() diff --git a/basic_plugins/admin_bot_manage/update_group_member_info.py b/basic_plugins/admin_bot_manage/update_group_member_info.py index a00bd8a8..4a5b2c4a 100755 --- a/basic_plugins/admin_bot_manage/update_group_member_info.py +++ b/basic_plugins/admin_bot_manage/update_group_member_info.py @@ -1,7 +1,12 @@ from nonebot import on_command, on_notice -from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, GROUP, GroupIncreaseNoticeEvent -from ._data_source import update_member_info +from nonebot.adapters.onebot.v11 import ( + GROUP, + Bot, + GroupIncreaseNoticeEvent, + GroupMessageEvent, +) +from ._data_source import update_member_info __zx_plugin_name__ = "更新群组成员列表 [Admin]" __plugin_usage__ = """ @@ -10,10 +15,10 @@ usage: 指令: 更新群组成员列表/更新群组成员信息 """.strip() -__plugin_des__ = '更新群组成员列表' -__plugin_cmd__ = ['更新群组成员列表'] +__plugin_des__ = "更新群组成员列表" +__plugin_cmd__ = ["更新群组成员列表"] __plugin_version__ = 0.1 -__plugin_author__ = 'HibiKier' +__plugin_author__ = "HibiKier" __plugin_settings__ = { "admin_level": 1, } @@ -25,8 +30,8 @@ refresh_member_group = on_command( @refresh_member_group.handle() -async def _(event: GroupMessageEvent): - if await update_member_info(event.group_id): +async def _(bot: Bot, event: GroupMessageEvent): + if await update_member_info(bot, event.group_id): await refresh_member_group.finish("更新群员信息成功!", at_sender=True) else: await refresh_member_group.finish("更新群员信息失败!", at_sender=True) @@ -38,4 +43,4 @@ group_increase_handle = on_notice(priority=1, block=False) @group_increase_handle.handle() async def _(bot: Bot, event: GroupIncreaseNoticeEvent): if event.user_id == int(bot.self_id): - await update_member_info(event.group_id) + await update_member_info(bot, event.group_id) diff --git a/basic_plugins/admin_help/data_source.py b/basic_plugins/admin_help/data_source.py index 28303a90..7bc78e1d 100755 --- a/basic_plugins/admin_help/data_source.py +++ b/basic_plugins/admin_help/data_source.py @@ -1,10 +1,10 @@ import nonebot -from configs.path_config import IMAGE_PATH from nonebot import Driver + +from configs.path_config import IMAGE_PATH from services.log import logger from utils.image_template import help_template -from utils.image_utils import (BuildImage, build_sort_image, group_image, - text2image) +from utils.image_utils import BuildImage, build_sort_image, group_image, text2image from utils.manager import group_manager, plugin_data_manager from utils.manager.models import PluginType @@ -23,13 +23,6 @@ async def init_task(): async def create_help_image(): - """ - 创建管理员帮助图片 - """ - await _create_help_image() - - -async def _create_help_image(): """ 创建管理员帮助图片 """ @@ -57,7 +50,9 @@ async def _create_help_image(): task_list.append(plugin_data.task[x]) except Exception as e: logger.warning( - f"获取群管理员插件 {plugin_data.model}: {plugin_data.name} 设置失败... {type(e)}:{e}" + f"获取群管理员插件 {plugin_data.model}: {plugin_data.name} 设置失败...", + "管理员帮助", + e=e, ) task_str = "\n".join(task_list) task_str = "通过 开启/关闭 来控制群被动\n----------\n" + task_str diff --git a/basic_plugins/apscheduler/__init__.py b/basic_plugins/apscheduler/__init__.py index 682597f0..545dba29 100755 --- a/basic_plugins/apscheduler/__init__.py +++ b/basic_plugins/apscheduler/__init__.py @@ -3,8 +3,7 @@ from pathlib import Path from typing import List import nonebot -from nonebot import on_message -from nonebot.adapters.onebot.v11 import ActionFailed +from nonebot import get_bots, on_message from configs.config import NICKNAME, Config from configs.path_config import IMAGE_PATH @@ -12,7 +11,7 @@ from models.friend_user import FriendUser from models.group_info import GroupInfo from services.log import logger from utils.message_builder import image -from utils.utils import broadcast_group, get_bot, scheduler +from utils.utils import broadcast_group, scheduler __zx_plugin_name__ = "定时任务相关 [Hidden]" __plugin_version__ = 0.1 @@ -58,7 +57,7 @@ cx = on_message(priority=9999, block=False, rule=lambda: False) async def _(): img = image(IMAGE_PATH / "zhenxun" / "zao.jpg") await broadcast_group("[[_task|zwa]]早上好" + img, log_cmd="被动早晚安") - logger.info("每日早安发送") + logger.info("每日早安发送...") # 睡觉了 @@ -72,7 +71,7 @@ async def _(): await broadcast_group( f"[[_task|zwa]]{NICKNAME}要睡觉了,你们也要早点睡呀" + img, log_cmd="被动早晚安" ) - logger.info("每日晚安发送") + logger.info("每日晚安发送...") # 自动更新群组信息 @@ -100,9 +99,10 @@ async def _(): "group_flag": 1, }, ) - logger.info(f"自动更新群组信息成功", group_id=g) + logger.debug("自动更新群组信息成功", "自动更新群组", group_id=g) except Exception as e: logger.error(f"Bot: {bot.self_id} 自动更新群组信息", e=e) + logger.info("自动更新群组成员信息成功...") # 自动更新好友信息 @@ -112,16 +112,17 @@ async def _(): minute=1, ) async def _(): - try: - bot = get_bot() - fl = await bot.get_friend_list() - for f in fl: - await FriendUser.create(user_id=f["user_id"], user_name=f["nickname"]) - logger.info(f'自动更新好友 {f["user_id"]} 信息成功') - # else: - # logger.warning(f'自动更新好友 {f["user_id"]} 信息失败') - except Exception as e: - logger.error(f"自动更新群组信息错误 e:{e}") + bots = nonebot.get_bots() + for key in bots: + try: + bot = bots[key] + fl = await bot.get_friend_list() + for f in fl: + await FriendUser.create(user_id=f["user_id"], user_name=f["nickname"]) + logger.debug(f"更新好友信息成功", "自动更新好友", f["user_id"]) + except Exception as e: + logger.error(f"自动更新群组信息错误", e=e) + logger.info("自动更新好友信息成功...") # 自动备份 @@ -134,22 +135,24 @@ async def _(): if Config.get_config("_backup", "BACKUP_FLAG"): _backup_path = Path() / "backup" _backup_path.mkdir(exist_ok=True, parents=True) - for x in Config.get_config("_backup", "BACKUP_DIR_OR_FILE"): - try: - path = Path(x) - _p = _backup_path / x - if path.exists(): - if path.is_dir(): - if _p.exists(): - shutil.rmtree(_p, ignore_errors=True) - shutil.copytree(x, _p) - else: - if _p.exists(): - _p.unlink() - shutil.copy(x, _p) - logger.info(f"已完成自动备份:{x}") - except Exception as e: - logger.error(f"自动备份文件 {x} 发生错误 {type(e)}:{e}") + if backup_dir_or_file := Config.get_config("_backup", "BACKUP_DIR_OR_FILE"): + for path_file in backup_dir_or_file: + try: + path = Path(path_file) + _p = _backup_path / path_file + if path.exists(): + if path.is_dir(): + if _p.exists(): + shutil.rmtree(_p, ignore_errors=True) + shutil.copytree(path_file, _p) + else: + if _p.exists(): + _p.unlink() + shutil.copy(path_file, _p) + logger.debug(f"已完成自动备份:{path_file}", "自动备份") + except Exception as e: + logger.error(f"自动备份文件 {path_file} 发生错误", "自动备份", e=e) + logger.info("自动备份成功...", "自动备份") # 一次性任务 diff --git a/basic_plugins/broadcast/__init__.py b/basic_plugins/broadcast/__init__.py index 1be81793..7563d3d8 100755 --- a/basic_plugins/broadcast/__init__.py +++ b/basic_plugins/broadcast/__init__.py @@ -1,4 +1,5 @@ import asyncio +from typing import List from nonebot import on_command from nonebot.adapters.onebot.v11 import Bot, Message, MessageEvent @@ -7,9 +8,9 @@ from nonebot.permission import SUPERUSER from configs.config import Config from services.log import logger +from utils.depends import ImageList from utils.manager import group_manager from utils.message_builder import image -from utils.utils import get_message_img __zx_plugin_name__ = "广播 [Superuser]" __plugin_usage__ = """ @@ -36,9 +37,13 @@ broadcast = on_command("广播-", priority=1, permission=SUPERUSER, block=True) @broadcast.handle() -async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): +async def _( + bot: Bot, + event: MessageEvent, + arg: Message = CommandArg(), + img_list: List[str] = ImageList(), +): msg = arg.extract_plain_text().strip() - img_list = get_message_img(event.json()) rst = "" for img in img_list: rst += image(img) @@ -58,9 +63,9 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): x += 0.25 try: await bot.send_group_msg(group_id=g, message=msg + rst) - logger.info(f"GROUP {g} 投递广播成功") + logger.info(f"投递广播成功", "广播", group_id=g) except Exception as e: - logger.error(f"GROUP {g} 投递广播失败:{type(e)}") + logger.error(f"投递广播失败", "广播", group_id=g, e=e) error += f"GROUP {g} 投递广播失败:{type(e)}\n" await asyncio.sleep(0.5) await broadcast.send(f"已播报至 100% 的群聊") diff --git a/basic_plugins/chat_history/_rule.py b/basic_plugins/chat_history/_rule.py index 71dee1f0..f794a177 100644 --- a/basic_plugins/chat_history/_rule.py +++ b/basic_plugins/chat_history/_rule.py @@ -1,6 +1,9 @@ from nonebot.adapters.onebot.v11 import Event, MessageEvent + from configs.config import Config def rule(event: Event) -> bool: - return Config.get_config("chat_history", "FLAG") and isinstance(event, MessageEvent) + return bool( + Config.get_config("chat_history", "FLAG") and isinstance(event, MessageEvent) + ) diff --git a/basic_plugins/group_handle/__init__.py b/basic_plugins/group_handle/__init__.py index e1dcea0f..bfa6ae5f 100755 --- a/basic_plugins/group_handle/__init__.py +++ b/basic_plugins/group_handle/__init__.py @@ -68,7 +68,7 @@ add_group = on_request(priority=1, block=False) @group_increase_handle.handle() async def _(bot: Bot, event: GroupIncreaseNoticeEvent): if event.user_id == int(bot.self_id): - group = await GroupInfo.filter(group_id=event.group_id).first() + group = await GroupInfo.get_or_none(group_id=event.group_id) # 群聊不存在或被强制拉群,退出该群 if (not group or group.group_flag == 0) and Config.get_config( "invite_manager", "flag" @@ -80,15 +80,15 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent): await bot.set_group_leave(group_id=event.group_id) await bot.send_private_msg( user_id=int(list(bot.config.superusers)[0]), - message=f"触发强制入群保护,已成功退出群聊 {event.group_id}..", + message=f"触发强制入群保护,已成功退出群聊 {event.group_id}...", ) - logger.info(f"强制拉群或未有群信息,退出群聊 {group} 成功") + logger.info(f"强制拉群或未有群信息,退出群聊成功", "入群检测", group_id=event.group_id) requests_manager.remove_request("group", event.group_id) except Exception as e: - logger.info(f"强制拉群或未有群信息,退出群聊 {group} 失败 e:{e}") + logger.info(f"强制拉群或未有群信息,退出群聊失败", "入群检测", group_id=event.group_id, e=e) await bot.send_private_msg( user_id=int(list(bot.config.superusers)[0]), - message=f"触发强制入群保护,退出群聊 {event.group_id} 失败..", + message=f"触发强制入群保护,退出群聊 {event.group_id} 失败...", ) # 默认群功能开关 elif event.group_id not in group_manager.get_data().group_manager.keys(): @@ -96,42 +96,53 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent): for plugin in data.keys(): if not data[plugin].default_status: group_manager.block_plugin(plugin, event.group_id) + admin_default_auth = Config.get_config( + "admin_bot_manage", "ADMIN_DEFAULT_AUTH" + ) # 即刻刷新权限 for user_info in await bot.get_group_member_list(group_id=event.group_id): - if user_info["role"] in [ - "owner", - "admin", - ] and not await LevelUser.is_group_flag( - user_info["user_id"], event.group_id + if ( + user_info["role"] + in [ + "owner", + "admin", + ] + and not await LevelUser.is_group_flag( + user_info["user_id"], event.group_id + ) + and admin_default_auth is not None ): await LevelUser.set_level( user_info["user_id"], user_info["group_id"], - Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH"), + admin_default_auth, + ) + logger.debug( + f"添加默认群管理员权限: {admin_default_auth}", + "入群检测", + user_info["user_id"], + user_info["group_id"], ) if str(user_info["user_id"]) in bot.config.superusers: await LevelUser.set_level( user_info["user_id"], user_info["group_id"], 9 ) + logger.debug( + f"添加超级用户权限: 9", + "入群检测", + user_info["user_id"], + user_info["group_id"], + ) else: join_time = datetime.now() user_info = await bot.get_group_member_info( group_id=event.group_id, user_id=event.user_id ) - user, _ = await GroupInfoUser.get_or_create( + await GroupInfoUser.update_or_create( user_qq=user_info["user_id"], group_id=user_info["group_id"], - defaults={ - "user_name": user_info["nickname"], - }, + defaults={"user_name": user_info["nickname"], "user_join_time": join_time}, ) - user.user_join_time = join_time - await user.save() - # await GroupInfoUser.update_or_create( - # user_qq=user_info["user_id"], - # group_id=user_info["group_id"], - # defaults={"user_name": user_info["nickname"], "user_join_time": join_time}, - # ) logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功") # 群欢迎消息 @@ -147,7 +158,7 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent): data = json.load(open(custom_welcome_msg_json, "r")) if data.get(str(event.group_id)): msg = data[str(event.group_id)] - if msg.find("[at]") != -1: + if "[at]" in msg: msg = msg.replace("[at]", "") at_flag = True if (DATA_PATH / "custom_welcome_msg" / f"{event.group_id}.jpg").exists(): diff --git a/basic_plugins/help/__init__.py b/basic_plugins/help/__init__.py index 925dc8f2..3e2a9a2c 100755 --- a/basic_plugins/help/__init__.py +++ b/basic_plugins/help/__init__.py @@ -1,23 +1,26 @@ -from nonebot import on_command -from nonebot.adapters.onebot.v11 import ( - Bot, - MessageEvent, - GroupMessageEvent, - Message -) -from nonebot.params import CommandArg -from nonebot.rule import to_me -from configs.path_config import IMAGE_PATH, DATA_PATH -from utils.message_builder import image -from ._data_source import create_help_img, get_plugin_help -from ._utils import GROUP_HELP_PATH import os +from nonebot import on_command +from nonebot.adapters.onebot.v11 import Bot, GroupMessageEvent, Message, MessageEvent +from nonebot.params import CommandArg +from nonebot.rule import to_me + +from configs.path_config import DATA_PATH, IMAGE_PATH +from services.log import logger +from utils.message_builder import image + +from ._data_source import create_help_img, get_plugin_help +from ._utils import GROUP_HELP_PATH __zx_plugin_name__ = "帮助" __plugin_configs__ = { - "TYPE": {"value": "normal", "help": "帮助图片样式 ['normal', 'HTML']", "default_value": "normal"} + "TYPE": { + "value": "normal", + "help": "帮助图片样式 ['normal', 'HTML']", + "default_value": "normal", + "type": str, + } } simple_help_image = IMAGE_PATH / "simple_help.png" @@ -25,7 +28,9 @@ if simple_help_image.exists(): simple_help_image.unlink() -simple_help = on_command("功能", rule=to_me(), aliases={"help", "帮助"}, priority=1, block=True) +simple_help = on_command( + "功能", rule=to_me(), aliases={"help", "帮助"}, priority=1, block=True +) @simple_help.handle() @@ -33,15 +38,18 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()): msg = arg.extract_plain_text().strip() is_super = False if msg: - if '-super' in msg: + if "-super" in msg: if str(event.user_id) in bot.config.superusers: is_super = True - msg = msg.replace('-super', '').strip() + msg = msg.replace("-super", "").strip() msg = get_plugin_help(msg, is_super) if msg: await simple_help.send(image(b64=msg)) else: await simple_help.send("没有此功能的帮助信息...") + logger.info( + f"查看帮助详情: {msg}", "帮助", event.user_id, getattr(event, "group_id", None) + ) else: if isinstance(event, GroupMessageEvent): _image_path = GROUP_HELP_PATH / f"{event.group_id}.png" diff --git a/basic_plugins/help/_data_source.py b/basic_plugins/help/_data_source.py index e53fa80c..be61b50b 100644 --- a/basic_plugins/help/_data_source.py +++ b/basic_plugins/help/_data_source.py @@ -1,14 +1,10 @@ +from typing import Optional + +from configs.path_config import IMAGE_PATH +from utils.image_utils import BuildImage +from utils.manager import admin_manager, plugin_data_manager, plugins2settings_manager from ._utils import HelpImageBuild -from utils.image_utils import BuildImage -from configs.path_config import IMAGE_PATH -from utils.manager import ( - plugins2settings_manager, - admin_manager, -) -from typing import Optional -import nonebot - random_bk_path = IMAGE_PATH / "background" / "help" / "simple_help" @@ -36,36 +32,25 @@ def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]: module = plugins2settings_manager.get_plugin_module( msg ) or admin_manager.get_plugin_module(msg) - if module: - try: - plugin = nonebot.plugin.get_plugin(module) - metadata = plugin.metadata - if plugin: - if is_super: - result = plugin.module.__getattribute__( - "__plugin_superuser_usage__" - ) - else: - result = ( - metadata.usage - if metadata - else plugin.module.__getattribute__("__plugin_usage__") - ) - if result: - width = 0 - for x in result.split("\n"): - _width = len(x) * 24 - width = width if width > _width else _width - height = len(result.split("\n")) * 45 - A = BuildImage(width, height, font_size=24) - bk = BuildImage( - width, - height, - background=IMAGE_PATH / "background" / "1.png", - ) - A.paste(bk, alpha=True) - A.text((int(width * 0.048), int(height * 0.21)), result) - return A.pic2bs4() - except AttributeError: - pass + if module and (plugin_data := plugin_data_manager.get(module)): + plugin_data.superuser_usage + if is_super: + result = plugin_data.superuser_usage + else: + result = plugin_data.usage + if result: + width = 0 + for x in result.split("\n"): + _width = len(x) * 24 + width = width if width > _width else _width + height = len(result.split("\n")) * 45 + A = BuildImage(width, height, font_size=24) + bk = BuildImage( + width, + height, + background=IMAGE_PATH / "background" / "1.png", + ) + A.paste(bk, alpha=True) + A.text((int(width * 0.048), int(height * 0.21)), result) + return A.pic2bs4() return None diff --git a/basic_plugins/help/_utils.py b/basic_plugins/help/_utils.py index 8de846ac..4a9ddad4 100644 --- a/basic_plugins/help/_utils.py +++ b/basic_plugins/help/_utils.py @@ -51,9 +51,9 @@ class HelpImageBuild: for key in self._data.keys(): plugin_data = self._data[key] if plugin_data.plugin_type == PluginType.NORMAL: - if not self._sort_data.get(plugin_data.menu_type[0]): - self._sort_data[plugin_data.menu_type[0]] = [] - self._sort_data[plugin_data.menu_type[0]].append(self._data[key]) + if not self._sort_data.get(plugin_data.menu_type[0]): # type: ignore + self._sort_data[plugin_data.menu_type[0]] = [] # type: ignore + self._sort_data[plugin_data.menu_type[0]].append(self._data[key]) # type: ignore async def build_image(self, group_id: Optional[int]): if group_id: @@ -71,6 +71,7 @@ class HelpImageBuild: async def build_html_image(self, group_id: Optional[int]) -> bytes: from nonebot_plugin_htmlrender import template_to_pic + self.sort_type() classify = {} for menu in self._sort_data: @@ -180,9 +181,12 @@ class HelpImageBuild: if ( not plugin_data.plugin_status.status and plugin_data.plugin_status.block_type in ["group", "all"] - ) or (group_id and not group_manager.get_plugin_super_status( - plugin_data.model, group_id - )): + ) or ( + group_id + and not group_manager.get_plugin_super_status( + plugin_data.model, group_id + ) + ): w = curr_h + int(B.getsize(plugin_data.name)[1] / 2) + 2 pos = ( 7, @@ -191,7 +195,7 @@ class HelpImageBuild: w, ) if build_type == "VV": - name_image = await self.build_name_image( + name_image = await self.build_name_image( # type: ignore max_width, plugin_data.name, "black" if not idx % 2 else "white", diff --git a/basic_plugins/hooks/_utils.py b/basic_plugins/hooks/_utils.py index fcf6cce0..4bd4f56e 100644 --- a/basic_plugins/hooks/_utils.py +++ b/basic_plugins/hooks/_utils.py @@ -1,7 +1,5 @@ import time -from typing import Optional -import nonebot from nonebot.adapters.onebot.v11 import ( Bot, Event, @@ -27,12 +25,14 @@ from utils.manager import ( StaticData, admin_manager, group_manager, + plugin_data_manager, plugins2block_manager, plugins2cd_manager, plugins2count_manager, plugins2settings_manager, plugins_manager, ) +from utils.manager.models import PluginType from utils.message_builder import at from utils.utils import FreqLimiter @@ -71,17 +71,17 @@ def set_block_limit_false(event, module): :param module: 插件模块 """ 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 - if not ( - (isinstance(event, GroupMessageEvent) and check_type == "private") - or (isinstance(event, PrivateMessageEvent) and check_type == "group") - ): - block_type_ = event.user_id - if limit_type == "group" and isinstance(event, GroupMessageEvent): - block_type_ = event.group_id - plugins2block_manager.set_false(block_type_, module) + if plugin_block_data := plugins2block_manager.get_plugin_block_data(module): + check_type = plugin_block_data.check_type + limit_type = plugin_block_data.limit_type + if not ( + (isinstance(event, GroupMessageEvent) and check_type == "private") + or (isinstance(event, PrivateMessageEvent) and check_type == "group") + ): + block_type_ = event.user_id + if limit_type == "group" and isinstance(event, GroupMessageEvent): + block_type_ = event.group_id + plugins2block_manager.set_false(block_type_, module) async def send_msg(msg: str, bot: Bot, event: MessageEvent): @@ -94,7 +94,7 @@ async def send_msg(msg: str, bot: Bot, event: MessageEvent): :param event: pass """ if "[uname]" in msg: - uname = event.sender.card or event.sender.nickname + uname = event.sender.card or event.sender.nickname or "" msg = msg.replace("[uname]", uname) if "[nickname]" in msg: if isinstance(event, GroupMessageEvent): @@ -128,10 +128,13 @@ class AuthChecker: """ 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")) + check_notice_info_cd = Config.get_config("hook", "CHECK_NOTICE_INFO_CD") + if check_notice_info_cd is None or check_notice_info_cd < 0: + raise ValueError("模块: [hook], 配置项: [CHECK_NOTICE_INFO_CD] 为空或小于0") + self._flmt = FreqLimiter(check_notice_info_cd) + self._flmt_g = FreqLimiter(check_notice_info_cd) + self._flmt_s = FreqLimiter(check_notice_info_cd) + self._flmt_c = FreqLimiter(check_notice_info_cd) async def auth(self, matcher: Matcher, bot: Bot, event: Event): """ @@ -142,22 +145,24 @@ class AuthChecker: :param bot: bot :param event: event """ + user_id = getattr(event, "user_id", None) + group_id = getattr(event, "group_id", None) try: if plugin_name := matcher.plugin_name: cost_gold = await self.auth_cost(plugin_name, bot, event) user_id = getattr(event, "user_id", None) + group_id = getattr(event, "group_id", None) if user_id and str(user_id) not in bot.config.superusers: 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: - await BagUser.spend_gold( - event.user_id, event.group_id, cost_gold - ) + if cost_gold and user_id and group_id: + await BagUser.spend_gold(user_id, group_id, cost_gold) + logger.debug(f"调用功能花费金币: {cost_gold}", "HOOK", user_id, group_id) except IsSuperuserException: - return + logger.debug(f"超级用户或被ban跳过权限检测...", "HOOK", user_id, group_id) async def auth_limit(self, plugin_name: str, bot: Bot, event: Event): """ @@ -168,62 +173,79 @@ class AuthChecker: :param bot: bot :param event: event """ + user_id = getattr(event, "user_id", None) + if not user_id: + return + group_id = getattr(event, "group_id", None) 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_) + plugin_cd_data := plugins2cd_manager.get_plugin_cd_data(plugin_name) + ) and (plugin_data := plugins2cd_manager.get_plugin_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 plugin_data.check_type == "all" + ): + cd_type_ = 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) # type: ignore + logger.debug( + f"{plugin_name} 正在cd中...", "HOOK", user_id, group_id + ) + 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" + if plugin_block_data := plugins2block_manager.get_plugin_block_data( + plugin_name ): - 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) + 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_ = 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) # type: ignore + logger.debug(f"正在调用{plugin_name}...", "HOOK", user_id, group_id) + raise IgnoredException(f"{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 + and 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_) + if 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_ = 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) # type: ignore + logger.debug( + f"{plugin_name} count次数限制...", "HOOK", user_id, group_id + ) + 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 @@ -241,66 +263,75 @@ class AuthChecker: 1, 999, ]: + user_id = getattr(event, "user_id", None) + if not user_id: + return + group_id = getattr(event, "group_id", None) # 戳一戳单独判断 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) + ) and group_id: + if status_message_manager.get(group_id) is None: + status_message_manager.delete(group_id) if plugins2settings_manager[ plugin_name - ].level > group_manager.get_group_level(event.group_id): + ].level > group_manager.get_group_level(group_id): try: if ( - self._flmt_g.check(event.user_id) + self._flmt_g.check(user_id) and plugin_name not in ignore_rst_module ): - self._flmt_g.start_cd(event.user_id) + self._flmt_g.start_cd(user_id) await bot.send_group_msg( - group_id=event.group_id, message="群权限不足..." + group_id=group_id, message="群权限不足..." ) except ActionFailed: pass if event.is_tome(): - status_message_manager.add(event.group_id) + status_message_manager.add(group_id) set_block_limit_false(event, plugin_name) + logger.debug(f"{plugin_name} 群权限不足...", "HOOK", user_id, group_id) raise IgnoredException("群权限不足") # 插件状态 - if not group_manager.get_plugin_status(plugin_name, event.group_id): + if not group_manager.get_plugin_status(plugin_name, group_id): try: if plugin_name not in ignore_rst_module and self._flmt_s.check( - event.group_id + group_id ): - self._flmt_s.start_cd(event.group_id) + self._flmt_s.start_cd(group_id) await bot.send_group_msg( - group_id=event.group_id, message="该群未开启此功能.." + group_id=group_id, message="该群未开启此功能.." ) except ActionFailed: pass if event.is_tome(): - status_message_manager.add(event.group_id) + status_message_manager.add(group_id) set_block_limit_false(event, plugin_name) + logger.debug(f"{plugin_name} 未开启此功能...", "HOOK", user_id, group_id) raise IgnoredException("未开启此功能...") # 管理员禁用 if not group_manager.get_plugin_status( - f"{plugin_name}:super", event.group_id + f"{plugin_name}:super", group_id ): try: if ( - self._flmt_s.check(event.group_id) + self._flmt_s.check(group_id) and plugin_name not in ignore_rst_module ): - self._flmt_s.start_cd(event.group_id) + self._flmt_s.start_cd(group_id) await bot.send_group_msg( - group_id=event.group_id, message="管理员禁用了此群该功能..." + group_id=group_id, message="管理员禁用了此群该功能..." ) except ActionFailed: pass if event.is_tome(): - status_message_manager.add(event.group_id) + status_message_manager.add(group_id) set_block_limit_false(event, plugin_name) + logger.debug( + f"{plugin_name} 管理员禁用了此群该功能...", "HOOK", user_id, group_id + ) raise IgnoredException("管理员禁用了此群该功能...") # 群聊禁用 if not plugins_manager.get_plugin_status( @@ -308,18 +339,21 @@ class AuthChecker: ): try: if ( - self._flmt_c.check(event.group_id) + self._flmt_c.check(group_id) and plugin_name not in ignore_rst_module ): - self._flmt_c.start_cd(event.group_id) + self._flmt_c.start_cd(group_id) await bot.send_group_msg( - group_id=event.group_id, message="该功能在群聊中已被禁用..." + group_id=group_id, message="该功能在群聊中已被禁用..." ) except ActionFailed: pass if event.is_tome(): - status_message_manager.add(event.group_id) + status_message_manager.add(group_id) set_block_limit_false(event, plugin_name) + logger.debug( + f"{plugin_name} 该插件在群聊中已被禁用...", "HOOK", user_id, group_id + ) raise IgnoredException("该插件在群聊中已被禁用...") else: # 私聊禁用 @@ -327,16 +361,19 @@ class AuthChecker: plugin_name, block_type="private" ): try: - if self._flmt_c.check(event.user_id): - self._flmt_c.start_cd(event.user_id) + if self._flmt_c.check(user_id): + self._flmt_c.start_cd(user_id) await bot.send_private_msg( - user_id=event.user_id, message="该功能在私聊中已被禁用..." + user_id=user_id, message="该功能在私聊中已被禁用..." ) except ActionFailed: pass if event.is_tome(): - status_message_manager.add(event.user_id) + status_message_manager.add(user_id) set_block_limit_false(event, plugin_name) + logger.debug( + f"{plugin_name} 该插件在私聊中已被禁用...", "HOOK", user_id, group_id + ) raise IgnoredException("该插件在私聊中已被禁用...") # 维护 if not plugins_manager.get_plugin_status(plugin_name, block_type="all"): @@ -357,18 +394,15 @@ class AuthChecker: ) else: await bot.send_private_msg( - user_id=event.user_id, message="此功能正在维护..." + user_id=user_id, message="此功能正在维护..." ) except ActionFailed: pass if event.is_tome(): - id_ = ( - event.group_id - if isinstance(event, GroupMessageEvent) - else event.user_id - ) + id_ = group_id or user_id status_message_manager.add(id_) set_block_limit_false(event, plugin_name) + logger.debug(f"{plugin_name} 此功能正在维护...", "HOOK", user_id, group_id) raise IgnoredException("此功能正在维护...") async def auth_admin( @@ -383,6 +417,10 @@ class AuthChecker: :param bot: bot :param event: event """ + user_id = getattr(event, "user_id", None) + if not user_id: + return + group_id = getattr(event, "group_id", None) if plugin_name in admin_manager.keys() and matcher.priority not in [1, 999]: if isinstance(event, GroupMessageEvent): # 个人权限 @@ -407,21 +445,23 @@ class AuthChecker: set_block_limit_false(event, plugin_name) if event.is_tome(): status_message_manager.add(event.group_id) - raise IgnoredException("权限不足") + logger.debug(f"{plugin_name} 管理员权限不足...", "HOOK", user_id, group_id) + raise IgnoredException("管理员权限不足") else: if not await LevelUser.check_level( - event.user_id, 0, admin_manager.get_plugin_level(plugin_name) + user_id, 0, admin_manager.get_plugin_level(plugin_name) ): try: await bot.send_private_msg( - user_id=event.user_id, + user_id=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) + status_message_manager.add(user_id) + logger.debug(f"{plugin_name} 管理员权限不足...", "HOOK", user_id, group_id) raise IgnoredException("权限不足") def auth_group(self, plugin_name: str, bot: Bot, event: Event): @@ -433,21 +473,26 @@ class AuthChecker: :param bot: bot :param event: event """ - if isinstance(event, GroupMessageEvent) or plugin_name in other_limit_plugins: + user_id = getattr(event, "user_id", None) + group_id = getattr(event, "group_id", None) + if not group_id: + return + if ( + group_manager.get_group_level(group_id) < 0 + and str(user_id) not in bot.config.superusers + ): + logger.debug(f"{plugin_name} 群黑名单, 群权限-1...", "HOOK", user_id, group_id) + raise IgnoredException("群黑名单") + if not group_manager.check_group_bot_status(group_id): 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 str(event.get_message()) != "醒来": + logger.debug( + f"{plugin_name} 功能总开关关闭状态...", "HOOK", user_id, group_id + ) + raise IgnoredException("功能总开关关闭状态") + except ValueError: + logger.debug(f"{plugin_name} 功能总开关关闭状态...", "HOOK", user_id, group_id) + raise IgnoredException("功能总开关关闭状态") async def auth_basic(self, plugin_name: str, bot: Bot, event: Event): """ @@ -458,32 +503,29 @@ class AuthChecker: :param bot: bot :param event: event """ - try: + user_id = getattr(event, "user_id", None) + if not user_id: + return + plugin_setting = plugins2settings_manager.get_plugin_data(plugin_name) + if ( + ( + not isinstance(event, MessageEvent) + and plugin_name not in other_limit_plugins + ) + or await BanUser.is_ban(user_id) + and str(user_id) not in bot.config.superusers + ) or ( + str(user_id) in bot.config.superusers + and plugin_setting + and not plugin_setting.limit_superuser + ): + raise IsSuperuserException() + if plugin_data := plugin_data_manager.get(plugin_name): 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 + plugin_data.plugin_type == PluginType.SUPERUSER + and str(user_id) in bot.config.superusers ): raise IsSuperuserException() - _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 IsSuperuserException() - except AttributeError: - pass async def auth_cost(self, plugin_name: str, bot: Bot, event: Event) -> int: """ @@ -494,6 +536,10 @@ class AuthChecker: :param bot: bot :param event: event """ + user_id = getattr(event, "user_id", None) + if not user_id: + return 0 + group_id = getattr(event, "group_id", None) cost_gold = 0 if isinstance(event, GroupMessageEvent) and ( psm := plugins2settings_manager.get_plugin_data(plugin_name) @@ -504,6 +550,12 @@ class AuthChecker: < psm.cost_gold ): await send_msg(f"金币不足..该功能需要{psm.cost_gold}金币..", bot, event) + logger.debug( + f"{plugin_name} 金币限制..该功能需要{psm.cost_gold}金币..", + "HOOK", + user_id, + group_id, + ) raise IgnoredException(f"{plugin_name} 金币限制...") # 当插件不阻塞超级用户时,超级用户提前扣除金币 if ( diff --git a/basic_plugins/hooks/ban_hook.py b/basic_plugins/hooks/ban_hook.py index 3f53684f..40d11b05 100755 --- a/basic_plugins/hooks/ban_hook.py +++ b/basic_plugins/hooks/ban_hook.py @@ -1,17 +1,11 @@ -from nonebot.adapters.onebot.v11 import ( - ActionFailed, - Bot, - Event, - GroupMessageEvent, - MessageEvent, - PokeNotifyEvent, -) +from nonebot.adapters.onebot.v11 import ActionFailed, Bot, Event, GroupMessageEvent from nonebot.matcher import Matcher from nonebot.message import IgnoredException, run_preprocessor from nonebot.typing import T_State from configs.config import Config from models.ban_user import BanUser +from services.log import logger from utils.message_builder import at from utils.utils import FreqLimiter, is_number, static_flmt @@ -30,26 +24,19 @@ _flmt = FreqLimiter(300) # 检查是否被ban @run_preprocessor async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State): - if hasattr(event, "user_id") and ( - ( - (isinstance(event, MessageEvent) or isinstance(event, PokeNotifyEvent)) - and matcher.priority not in [1, 999] - ) - or matcher.plugin_name in other_limit_plugins + user_id = getattr(event, "user_id", None) + group_id = getattr(event, "group_id", None) + if user_id and ( + matcher.priority not in [1, 999] or matcher.plugin_name in other_limit_plugins ): - try: - if ( - await BanUser.is_super_ban(event.user_id) - and str(event.user_id) not in bot.config.superusers - ): - raise IgnoredException("用户处于超级黑名单中") - except AttributeError: - pass if ( - await BanUser.is_ban(event.user_id) - and str(event.user_id) not in bot.config.superusers + await BanUser.is_super_ban(user_id) + and str(user_id) not in bot.config.superusers ): - time = await BanUser.check_ban_time(event.user_id) + logger.debug(f"用户处于超级黑名单中...", "HOOK", user_id, group_id) + raise IgnoredException("用户处于超级黑名单中") + if await BanUser.is_ban(user_id) and str(user_id) not in bot.config.superusers: + time = await BanUser.check_ban_time(user_id) if isinstance(time, int): time = abs(int(time)) if time < 60: @@ -59,40 +46,38 @@ async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State): else: time = str(time) + " 分钟" if isinstance(event, GroupMessageEvent): - if not static_flmt.check(event.user_id): + if not static_flmt.check(user_id): + logger.debug(f"用户处于黑名单中...", "HOOK", user_id, group_id) raise IgnoredException("用户处于黑名单中") - static_flmt.start_cd(event.user_id) + static_flmt.start_cd(user_id) if matcher.priority != 999: try: ban_result = Config.get_config("hook", "BAN_RESULT") if ( ban_result - and _flmt.check(event.user_id) + and _flmt.check(user_id) and matcher.plugin_name not in ignore_rst_module ): - _flmt.start_cd(event.user_id) + _flmt.start_cd(user_id) await bot.send_group_msg( group_id=event.group_id, - message=at(event.user_id) + message=at(user_id) + ban_result + f" 在..在 {time} 后才会理你喔", ) except ActionFailed: pass else: - if not static_flmt.check(event.user_id): + if not static_flmt.check(user_id): + logger.debug(f"用户处于黑名单中...", "HOOK", user_id, group_id) raise IgnoredException("用户处于黑名单中") - static_flmt.start_cd(event.user_id) + static_flmt.start_cd(user_id) if matcher.priority != 999: - try: - ban_result = Config.get_config("hook", "BAN_RESULT") - if ban_result and matcher.plugin_name not in ignore_rst_module: - await bot.send_private_msg( - user_id=event.user_id, - message=at(event.user_id) - + ban_result - + f" 在..在 {time}后才会理你喔", - ) - except ActionFailed: - pass + ban_result = Config.get_config("hook", "BAN_RESULT") + if ban_result and matcher.plugin_name not in ignore_rst_module: + await bot.send_private_msg( + user_id=user_id, + message=at(user_id) + ban_result + f" 在..在 {time}后才会理你喔", + ) + logger.debug(f"用户处于黑名单中...", "HOOK", user_id, group_id) raise IgnoredException("用户处于黑名单中") diff --git a/basic_plugins/hooks/chkdsk_hook.py b/basic_plugins/hooks/chkdsk_hook.py index 46c53410..5b506c97 100755 --- a/basic_plugins/hooks/chkdsk_hook.py +++ b/basic_plugins/hooks/chkdsk_hook.py @@ -1,39 +1,54 @@ -from nonebot.matcher import Matcher -from nonebot.message import run_preprocessor, IgnoredException -from nonebot.typing import T_State from nonebot.adapters.onebot.v11 import ( - Bot, ActionFailed, - MessageEvent, + Bot, GroupMessageEvent, + MessageEvent, ) +from nonebot.matcher import Matcher +from nonebot.message import IgnoredException, run_preprocessor +from nonebot.typing import T_State + from configs.config import Config from models.ban_user import BanUser -from utils.utils import BanCheckLimiter -from utils.message_builder import at from services.log import logger +from utils.message_builder import at +from utils.utils import BanCheckLimiter +malicious_check_time = Config.get_config("hook", "MALICIOUS_CHECK_TIME") +malicious_ban_count = Config.get_config("hook", "MALICIOUS_BAN_COUNT") + +if not malicious_check_time: + raise ValueError("模块: [hook], 配置项: [MALICIOUS_CHECK_TIME] 为空或小于0") +if not malicious_ban_count: + raise ValueError("模块: [hook], 配置项: [MALICIOUS_BAN_COUNT] 为空或小于0") _blmt = BanCheckLimiter( - Config.get_config("hook", "MALICIOUS_CHECK_TIME"), - Config.get_config("hook", "MALICIOUS_BAN_COUNT"), + malicious_check_time, + malicious_ban_count, ) # 恶意触发命令检测 @run_preprocessor async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State): + user_id = getattr(event, "user_id", None) + group_id = getattr(event, "group_id", None) if not isinstance(event, MessageEvent): return + malicious_ban_time = Config.get_config("hook", "MALICIOUS_BAN_TIME") + if not malicious_ban_time: + raise ValueError("模块: [hook], 配置项: [MALICIOUS_BAN_TIME] 为空或小于0") if matcher.type == "message" and matcher.priority not in [1, 999]: if state["_prefix"]["raw_command"]: if _blmt.check(f'{event.user_id}{state["_prefix"]["raw_command"]}'): await BanUser.ban( event.user_id, 9, - Config.get_config("hook", "MALICIOUS_BAN_TIME") * 60, + malicious_ban_time * 60, + ) + logger.info( + f"触发了恶意触发检测: {matcher.plugin_name}", "HOOK", user_id, group_id ) - logger.info(f"USER {event.user_id} 触发了恶意触发检测") if isinstance(event, GroupMessageEvent): try: await bot.send_group_msg( @@ -50,5 +65,8 @@ async def _(matcher: Matcher, bot: Bot, event: GroupMessageEvent, state: T_State ) except ActionFailed: pass + logger.debug( + f"触发了恶意触发检测: {matcher.plugin_name}", "HOOK", user_id, group_id + ) raise IgnoredException("检测到恶意触发命令") _blmt.add(f'{event.user_id}{state["_prefix"]["raw_command"]}') diff --git a/basic_plugins/hooks/task_hook.py b/basic_plugins/hooks/task_hook.py index 5b5465ff..24039559 100644 --- a/basic_plugins/hooks/task_hook.py +++ b/basic_plugins/hooks/task_hook.py @@ -1,9 +1,11 @@ -from nonebot.exception import MockApiException -from nonebot.adapters.onebot.v11 import Bot, Message -from utils.manager import group_manager -from services.log import logger -from typing import Dict, Any import re +from typing import Any, Dict + +from nonebot.adapters.onebot.v11 import Bot, Message +from nonebot.exception import MockApiException + +from services.log import logger +from utils.manager import group_manager @Bot.on_calling_api @@ -40,13 +42,13 @@ async def _(bot: Bot, api: str, data: Dict[str, Any]): task = r.group(1) group_id = data["group_id"] except Exception as e: - logger.error(f"TaskHook ERROR {type(e)}:{e}") + logger.error(f"TaskHook ERROR", "HOOK", e=e) else: if task and group_id: - if ( - group_manager.get_group_level(group_id) < 0 - or not group_manager.check_task_status(task, group_id) - ): + if group_manager.get_group_level( + group_id + ) < 0 or not group_manager.check_task_status(task, group_id): + logger.debug(f"被动技能 {task} 处于关闭状态") raise MockApiException(f"被动技能 {task} 处于关闭状态...") else: msg = str(data["message"]).strip() diff --git a/basic_plugins/hooks/withdraw_message_hook.py b/basic_plugins/hooks/withdraw_message_hook.py index 92cbc861..db7d5651 100755 --- a/basic_plugins/hooks/withdraw_message_hook.py +++ b/basic_plugins/hooks/withdraw_message_hook.py @@ -1,10 +1,13 @@ +import asyncio +from typing import Optional + +from nonebot.adapters.onebot.v11 import Bot, Event from nonebot.matcher import Matcher from nonebot.message import run_postprocessor -from typing import Optional from nonebot.typing import T_State -from nonebot.adapters.onebot.v11 import Bot, Event + +from services.log import logger from utils.manager import withdraw_message_manager -import asyncio # 消息撤回 @@ -25,4 +28,5 @@ async def _( async def _withdraw_message(bot: Bot, id_: int, time: int): await asyncio.sleep(time) + logger.debug(f"撤回消息ID: {id_}", "HOOK") await bot.delete_msg(message_id=id_) diff --git a/basic_plugins/invite_manager/__init__.py b/basic_plugins/invite_manager/__init__.py index a9becf02..bf6dbbee 100755 --- a/basic_plugins/invite_manager/__init__.py +++ b/basic_plugins/invite_manager/__init__.py @@ -41,7 +41,7 @@ x = on_message(priority=999, block=False, rule=lambda: False) @friend_req.handle() async def _(bot: Bot, event: FriendRequestEvent): if time_manager.add_user_request(event.user_id): - logger.debug(f"收录 用户[{event.user_id}] 好友请求", "好友请求") + logger.debug(f"收录好友请求...", "好友请求", target=event.user_id) user = await bot.get_stranger_info(user_id=event.user_id) nickname = user["nickname"] sex = user["sex"] diff --git a/basic_plugins/plugin_shop/data_source.py b/basic_plugins/plugin_shop/data_source.py index e582ded5..815527df 100644 --- a/basic_plugins/plugin_shop/data_source.py +++ b/basic_plugins/plugin_shop/data_source.py @@ -105,7 +105,7 @@ async def uninstall_plugin(name: str) -> str: logger.info(f"插件 {name} 删除成功!") return f"插件 {name} 删除成功!" except Exception as e: - logger.error(f"删除插件 {name} 失败 {type(e)}:{e}") + logger.error(f"删除插件失败", target=name, e=e) return f"删除插件 {name} 失败 {type(e)}:{e}" @@ -183,19 +183,18 @@ async def download_json() -> int: shutil.rmtree(extract_path.absolute(), ignore_errors=True) return 200 except Exception as e: - logger.error(f"下载插件库压缩包失败或解压失败 {type(e)}:{e}") + logger.error(f"下载插件库压缩包失败或解压失败", e=e) return 999 -async def get_plugin_name(name: int) -> Tuple[str, int]: +async def get_plugin_name(index: int) -> Tuple[str, int]: """ 通过下标获取插件名 :param name: 下标 """ - name = int(name) if not data: await show_plugin_repo() - if name < 1 or name > len(data.keys()): + if index < 1 or index > len(data.keys()): return "下标超过上下限!", 999 - name = list(data.keys())[name - 1] + name = list(data.keys())[index - 1] return name, 200 diff --git a/basic_plugins/shop/my_props/__init__.py b/basic_plugins/shop/my_props/__init__.py index fc3bd6cf..a634fb52 100644 --- a/basic_plugins/shop/my_props/__init__.py +++ b/basic_plugins/shop/my_props/__init__.py @@ -36,6 +36,6 @@ async def _(event: GroupMessageEvent): props = await BagUser.get_property(event.user_id, event.group_id) if props: await my_props.send(image(b64=await create_bag_image(props))) - logger.info(f"USER {event.user_id} GROUP {event.group_id} 查看我的道具") + logger.info(f"查看我的道具", "我的道具", event.user_id, event.group_id) else: await my_props.finish("您的背包里没有任何的道具噢~", at_sender=True) diff --git a/basic_plugins/shop/shop_handle/__init__.py b/basic_plugins/shop/shop_handle/__init__.py index 9748330a..d436f78b 100644 --- a/basic_plugins/shop/shop_handle/__init__.py +++ b/basic_plugins/shop/shop_handle/__init__.py @@ -92,10 +92,10 @@ async def _(event: MessageEvent, arg: Message = CommandArg()): f"限时:{data.get('limit_time')}", at_sender=True, ) - logger.info(f"USER {event.user_id} 添加商品 {msg} 成功") + logger.info(f"添加商品 {msg} 成功", "添加商品", event.user_id) else: await shop_add_goods.send(f"添加商品 {msg} 失败了...", at_sender=True) - logger.warning(f"USER {event.user_id} 添加商品 {msg} 失败") + logger.warning(f"添加商品 {msg} 失败", "添加商品", event.user_id) @shop_del_goods.handle() @@ -113,10 +113,10 @@ async def _(event: MessageEvent, arg: Message = CommandArg()): await shop_del_goods.send(f"删除商品 {goods_name} 成功了...", at_sender=True) if os.path.exists(f"{IMAGE_PATH}/shop_help.png"): os.remove(f"{IMAGE_PATH}/shop_help.png") - logger.info(f"USER {event.user_id} 删除商品 {goods_name} 成功") + logger.info(f"删除商品成功", "删除商品", event.user_id, target=goods_name) else: await shop_del_goods.send(f"删除商品 {goods_name} 失败了...", at_sender=True) - logger.info(f"USER {event.user_id} 删除商品 {goods_name} 失败") + logger.info(f"删除商品失败", "删除商品", event.user_id, target=goods_name) @shop_update_goods.handle() @@ -131,10 +131,10 @@ async def _(event: MessageEvent, arg: Message = CommandArg()): flag, name, text = await update_goods(**data) if flag: await shop_update_goods.send(f"修改商品 {name} 成功了...\n{text}", at_sender=True) - logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 成功") + logger.info(f"修改商品数据 {text} 成功", "修改商品", event.user_id, target=name) else: await shop_update_goods.send(name, at_sender=True) - logger.info(f"USER {event.user_id} 修改商品 {name} 数据 {text} 失败") + logger.info(f"修改商品数据 {text} 失败", "修改商品", event.user_id, target=name) @scheduler.scheduled_job( @@ -147,7 +147,7 @@ async def _(): await GoodsInfo.all().update(daily_purchase_limit={}) logger.info("商品每日限购次数重置成功...") except Exception as e: - logger.error(f"商品每日限购次数重置出错 {type(e)}:{e}") + logger.error(f"商品每日限购次数重置出错", e=e) @scheduler.scheduled_job( diff --git a/basic_plugins/shop/shop_handle/data_source.py b/basic_plugins/shop/shop_handle/data_source.py index a4b90e23..4f10ce5d 100644 --- a/basic_plugins/shop/shop_handle/data_source.py +++ b/basic_plugins/shop/shop_handle/data_source.py @@ -1,5 +1,5 @@ import time -from typing import Optional, Tuple, Union +from typing import List, Optional, Tuple, Union from PIL import Image @@ -25,7 +25,7 @@ async def create_shop_help() -> str: _dc = {} font_h = BuildImage(0, 0).getsize("正")[1] h = 10 - _list = [] + _list: List[GoodsInfo] = [] for goods in goods_lst: if goods.goods_limit_time == 0 or time.time() < goods.goods_limit_time: _list.append(goods) diff --git a/basic_plugins/shop/use/__init__.py b/basic_plugins/shop/use/__init__.py index 57cc5c00..9e37542e 100644 --- a/basic_plugins/shop/use/__init__.py +++ b/basic_plugins/shop/use/__init__.py @@ -97,9 +97,7 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()): await use_props.send(f"使用道具 {name} {num} 次成功!", at_sender=True) if msg := await effect(bot, event, name, num, text, event.message): await use_props.send(msg, at_sender=True) - logger.info( - f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次成功" - ) + logger.info(f"使用道具 {name} {num} 次成功", event.user_id, event.group_id) await UserShopGoldLog.create( user_qq=event.user_id, group_id=event.group_id, @@ -110,7 +108,7 @@ async def _(bot: Bot, event: GroupMessageEvent, arg: Message = CommandArg()): else: await use_props.send(f"使用道具 {name} {num} 次失败!", at_sender=True) logger.info( - f"USER {event.user_id} GROUP {event.group_id} 使用道具 {name} {num} 次失败" + f"使用道具 {name} {num} 次失败", "使用道具", event.user_id, event.group_id ) await func_manager.run_handle(type_="after_handle", param=model, **kwargs) else: diff --git a/basic_plugins/super_cmd/manager_group.py b/basic_plugins/super_cmd/manager_group.py index b1add260..ed250684 100755 --- a/basic_plugins/super_cmd/manager_group.py +++ b/basic_plugins/super_cmd/manager_group.py @@ -205,40 +205,31 @@ async def _( if not msg: await manager_group_whitelist.finish("请输入群号") error_group = [] - all_group = [g["group_id"] for g in await bot.get_group_list()] for group_id in msg: group_id = int(group_id) - if is_number(group_id) and group_id in all_group: - if cmd[:2] == "添加": - try: - group_info = await bot.get_group_info(group_id=group_id) - await GroupInfo.update_or_create( - group_id=group_info["group_id"], - defaults={ - "group_flag": 1, - "group_name": group_info["group_name"], - "max_member_count": group_info["max_member_count"], - "member_count": group_info["member_count"], - }, - ) - except Exception as e: - await group_auth.send(f"添加群认证 {group_id} 发生错误!") - logger.error(f"添加群认证发生错误", cmd, target=group_id, e=e) - else: - await group_auth.send(f"已为 {group_id} {cmd[:2]}群认证..") - logger.info(f"添加群认证成功", cmd, target=group_id) + if cmd[:2] == "添加": + try: + await GroupInfo.update_or_create( + group_id=group_id, + defaults={ + "group_flag": 1, + }, + ) + except Exception as e: + await group_auth.send(f"添加群认证 {group_id} 发生错误!") + logger.error(f"添加群认证发生错误", cmd, target=group_id, e=e) else: - if group := await GroupInfo.filter(group_id=group_id).first(): - await group.update_or_create( - group_id=group_id, defaults={"group_flag": 0} - ) - await group_auth.send(f"已删除 {group_id} 群认证..") - logger.info(f"删除群认证成功", cmd, target=group_id) - else: - await group_auth.send(f"未查找到群聊: {group_id}") - logger.info(f"未找到群聊", cmd, target=group_id) + await group_auth.send(f"已为 {group_id} {cmd[:2]}群认证..") + logger.info(f"添加群认证成功", cmd, target=group_id) else: - logger.debug(f"群号不合法或不存在", cmd, target=group_id) - error_group.append(str(group_id)) + if group := await GroupInfo.filter(group_id=group_id).first(): + await group.update_or_create( + group_id=group_id, defaults={"group_flag": 0} + ) + await group_auth.send(f"已删除 {group_id} 群认证..") + logger.info(f"删除群认证成功", cmd, target=group_id) + else: + await group_auth.send(f"未查找到群聊: {group_id}") + logger.info(f"未找到群聊", cmd, target=group_id) if error_group: await manager_group_whitelist.send("以下群聊不合法或不存在:\n" + "\n".join(error_group)) diff --git a/basic_plugins/super_help/data_source.py b/basic_plugins/super_help/data_source.py index 6f22253e..655ea5a1 100755 --- a/basic_plugins/super_help/data_source.py +++ b/basic_plugins/super_help/data_source.py @@ -1,11 +1,10 @@ - import nonebot -from configs.path_config import IMAGE_PATH from nonebot import Driver + +from configs.path_config import IMAGE_PATH from services.log import logger from utils.image_template import help_template -from utils.image_utils import (BuildImage, build_sort_image, group_image, - text2image) +from utils.image_utils import BuildImage, build_sort_image, group_image, text2image from utils.manager import plugin_data_manager from utils.manager.models import PluginType @@ -52,13 +51,11 @@ async def create_help_image(): task_list.append(plugin_data.task[x]) except Exception as e: logger.warning( - f"获取超级用户插件 {plugin_data.model}: {plugin_data.name} 设置失败... {type(e)}:{e}" + f"获取超级用户插件 {plugin_data.model}: {plugin_data.name} 设置失败...", e=e ) task_str = "\n".join(task_list) task_str = "通过私聊 开启被动/关闭被动 + [被动名称] 来控制全局被动\n----------\n" + task_str - task_image = await text2image( - task_str, padding=5, color=(204, 196, 151) - ) + task_image = await text2image(task_str, padding=5, color=(204, 196, 151)) task_image = await help_template("被动任务", task_image) image_list.append(task_image) image_group, _ = group_image(image_list) diff --git a/basic_plugins/update_info.py b/basic_plugins/update_info.py index 074d72a9..a5896f23 100755 --- a/basic_plugins/update_info.py +++ b/basic_plugins/update_info.py @@ -27,6 +27,6 @@ update_info = on_command("更新信息", aliases={"更新日志"}, priority=5, b @update_info.handle() async def _(): if img := image("update_info.png"): - await update_info.finish(image("update_info.png")) + await update_info.finish(img) else: await update_info.finish("目前没有更新信息哦") diff --git a/models/group_member_info.py b/models/group_member_info.py index fc03b32f..cb9e4751 100755 --- a/models/group_member_info.py +++ b/models/group_member_info.py @@ -113,5 +113,6 @@ class GroupInfoUser(Model): @classmethod async def _run_script(cls): return [ - "alter table group_info_users alter user_join_time drop not null;" # 允许 user_join_time 为空 + "alter table group_info_users alter user_join_time drop not null;", # 允许 user_join_time 为空 + "ALTER TABLE group_info_users ALTER COLUMN user_join_time TYPE timestamp with time zone USING user_join_time::timestamp with time zone;", ] diff --git a/plugins/open_cases/build_image.py b/plugins/open_cases/build_image.py index c60a6a42..8f4c586c 100644 --- a/plugins/open_cases/build_image.py +++ b/plugins/open_cases/build_image.py @@ -14,7 +14,7 @@ BASE_PATH = IMAGE_PATH / "csgo_cases" ICON_PATH = IMAGE_PATH / "_icon" -async def generate_skin(skin: BuffSkin) -> Optional[BuildImage]: +async def generate_skin(skin: BuffSkin, update_count: int) -> Optional[BuildImage]: """构造皮肤图片 Args: @@ -53,13 +53,19 @@ async def generate_skin(skin: BuffSkin) -> Optional[BuildImage]: (340, 116), str(skin.sell_min_price), (0, 255, 98), font_size=30 ) - price_icon = BuildImage(30, 30, background=ICON_PATH / "num_white.png") - await case_bk.apaste(price_icon, (455, 70), True) + update_count_icon = BuildImage( + 40, 40, background=ICON_PATH / "reload_white.png" + ) + await case_bk.apaste(update_count_icon, (575, 10), True) + await case_bk.atext((625, 12), str(update_count), (255, 255, 255), font_size=45) + + num_icon = BuildImage(30, 30, background=ICON_PATH / "num_white.png") + await case_bk.apaste(num_icon, (455, 70), True) await case_bk.atext((490, 75), "在售:", (255, 255, 255)) await case_bk.atext((535, 72), str(skin.sell_num), (144, 0, 255), font_size=30) - price_icon = BuildImage(30, 30, background=ICON_PATH / "want_buy_white.png") - await case_bk.apaste(price_icon, (455, 114), True) + want_buy_icon = BuildImage(30, 30, background=ICON_PATH / "want_buy_white.png") + await case_bk.apaste(want_buy_icon, (455, 114), True) await case_bk.atext((490, 120), "求购:", (255, 255, 255)) await case_bk.atext((535, 116), str(skin.buy_num), (144, 0, 255), font_size=30) @@ -81,14 +87,19 @@ async def generate_skin(skin: BuffSkin) -> Optional[BuildImage]: 235, 250, color=(25, 25, 25, 100), font_size=25, font="CJGaoDeGuo.otf" ) skin_image = BuildImage(205, 153, background=file_path) - skin_bk.paste(skin_image, (10, 30), alpha=True) - # skin_bk.paste(circular_red, (-20, 10), True) - skin_bk.line((10, 180, 220, 180)) - skin_bk.text((10, 10), skin.name, (255, 255, 255)) - skin_bk.text((10, 185), f"{skin.skin_name}", (255, 255, 255), "by_width") - skin_bk.text((10, 218), "品质:", (255, 255, 255)) - skin_bk.text((55, 218), COLOR2NAME[skin.color][:2], COLOR2COLOR[skin.color]) - skin_bk.text((100, 218), "类型:", (255, 255, 255)) - skin_bk.text((145, 218), skin.weapon_type, (255, 255, 255)) + update_count_icon = BuildImage( + 35, 35, background=ICON_PATH / "reload_white.png" + ) + await skin_bk.apaste(skin_image, (10, 30), alpha=True) + await skin_bk.aline((10, 180, 220, 180)) + await skin_bk.atext((10, 10), skin.name, (255, 255, 255)) + await skin_bk.apaste(update_count_icon, (140, 10), True) + await skin_bk.atext((175, 15), str(update_count), (255, 255, 255)) + await skin_bk.atext((10, 185), f"{skin.skin_name}", (255, 255, 255), "by_width") + await skin_bk.atext((10, 218), "品质:", (255, 255, 255)) + await skin_bk.atext( + (55, 218), COLOR2NAME[skin.color][:2], COLOR2COLOR[skin.color] + ) + await skin_bk.atext((100, 218), "类型:", (255, 255, 255)) + await skin_bk.atext((145, 218), skin.weapon_type, (255, 255, 255)) return skin_bk - return None diff --git a/plugins/open_cases/models/buff_skin.py b/plugins/open_cases/models/buff_skin.py index 60b7faa9..27ab3eba 100644 --- a/plugins/open_cases/models/buff_skin.py +++ b/plugins/open_cases/models/buff_skin.py @@ -49,6 +49,7 @@ class BuffSkin(Model): class Meta: table = "buff_skin" table_description = "Buff皮肤数据表" + unique_together = ("case_name", "name", "skin_name", "abrasion") @classmethod async def random_skin( diff --git a/plugins/open_cases/utils.py b/plugins/open_cases/utils.py index 5d91ce0a..aeefee5f 100755 --- a/plugins/open_cases/utils.py +++ b/plugins/open_cases/utils.py @@ -6,6 +6,7 @@ from datetime import datetime from typing import List, Tuple, Union import nonebot +from tortoise.functions import Count from configs.config import Config from configs.path_config import IMAGE_PATH @@ -273,7 +274,14 @@ async def build_case_image(case_name: str) -> Union[BuildImage, str]: background = random.choice(os.listdir(CASE_BACKGROUND)) background_img = BuildImage(0, 0, background=CASE_BACKGROUND / background) if case_name: + log_list = ( + await BuffSkinLog.filter(case_name=case_name) + .annotate(count=Count("id")) + .group_by("skin_name") + .values_list("skin_name", "count") + ) skin_list_ = await BuffSkin.filter(case_name=case_name).all() + skin2count = {item[0]: item[1] for item in log_list} case = None skin_list: List[BuffSkin] = [] exists_name = [] @@ -287,7 +295,7 @@ async def build_case_image(case_name: str) -> Union[BuildImage, str]: exists_name.append(name) generate_img = {} for skin in skin_list: - skin_img = await generate_skin(skin) + skin_img = await generate_skin(skin, skin2count[skin.skin_name]) if skin_img: if not generate_img.get(skin.color): generate_img[skin.color] = [] @@ -305,7 +313,7 @@ async def build_case_image(case_name: str) -> Union[BuildImage, str]: ) await A.afilter("GaussianBlur", 2) if case: - case_img = await generate_skin(case) + case_img = await generate_skin(case, skin2count[f"{case_name}武器箱"]) if case_img: A.paste(case_img, (25, 25), True) w = 25 @@ -321,10 +329,17 @@ async def build_case_image(case_name: str) -> Union[BuildImage, str]: await A.acrop((0, 0, A.w, h + img_h + 100)) return A else: + log_list = ( + await BuffSkinLog.filter(color="CASE") + .annotate(count=Count("id")) + .group_by("case_name") + .values_list("case_name", "count") + ) + name2count = {item[0]: item[1] for item in log_list} skin_list = await BuffSkin.filter(color="CASE").all() image_list: List[BuildImage] = [] for skin in skin_list: - if img := await generate_skin(skin): + if img := await generate_skin(skin, name2count[skin.case_name]): image_list.append(img) if not image_list: return "未收录武器箱" diff --git a/plugins/sign_in/utils.py b/plugins/sign_in/utils.py index 30cea6d3..4d47efd5 100755 --- a/plugins/sign_in/utils.py +++ b/plugins/sign_in/utils.py @@ -148,7 +148,7 @@ def _generate_card( ratio = 1 - (next_impression - user.impression) / ( next_impression - previous_impression ) - bar.resize(w=int(bar.w * ratio), h=bar.h) + bar.resize(w=int(bar.w * ratio) or 1, h=bar.h) bar_bk.paste( bar, alpha=True, diff --git a/resources/image/_icon/reload_white.png b/resources/image/_icon/reload_white.png new file mode 100644 index 0000000000000000000000000000000000000000..e5c5f98a5a97cdd7d7c884abf87da965cde83cba GIT binary patch literal 4227 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 literal 0 HcmV?d00001