From 026ce8c773a019815ae64859c1193fd89c1b4224 Mon Sep 17 00:00:00 2001 From: baby20162016 <2185823427@qq.com> Date: Fri, 2 Jan 2026 17:40:57 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=8F=92=E4=BB=B6admin?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E5=9C=A8models=E4=B8=AD=E6=96=B0=E5=A2=9EPlu?= =?UTF-8?q?ginDataManager=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/__init__.py | 3 +- core/plugin_manager.py | 85 +++++++++++++++++++++++++++-- plugins/admin.py | 115 ++++++++++++++++++++++++++++++++++++++++ plugins/data/admin.json | 1 + plugins/thpic.py | 8 +-- 5 files changed, 202 insertions(+), 10 deletions(-) create mode 100644 plugins/admin.py create mode 100644 plugins/data/admin.json diff --git a/core/__init__.py b/core/__init__.py index dc3ae5d..032d0c6 100644 --- a/core/__init__.py +++ b/core/__init__.py @@ -1,5 +1,6 @@ from .command_manager import matcher from .config_loader import global_config +from .plugin_manager import PluginDataManager from .ws import WS -__all__ = ["WS", "matcher", "global_config"] +__all__ = ["WS", "matcher", "global_config", "PluginDataManager"] diff --git a/core/plugin_manager.py b/core/plugin_manager.py index df15828..9a1e039 100644 --- a/core/plugin_manager.py +++ b/core/plugin_manager.py @@ -3,7 +3,9 @@ 负责扫描、加载和管理 `base_plugins` 目录下的所有插件。 """ + import importlib +import json import os import pkgutil import sys @@ -18,10 +20,12 @@ def load_all_plugins(): 该函数会遍历 `plugins` 目录下的所有模块: 1. 如果模块已加载,则执行 reload 操作(用于热重载)。 2. 如果模块未加载,则执行 import 操作。 - + 加载过程中会提取插件元数据 `__plugin_meta__` 并注册到 CommandManager。 """ - plugin_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "plugins") + plugin_dir = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "..", "plugins" + ) package_name = "plugins" print(f" 正在从 {package_name} 加载插件...") @@ -36,13 +40,84 @@ def load_all_plugins(): else: module = importlib.import_module(full_module_name) action = "加载" - + # 提取插件元数据 if hasattr(module, "__plugin_meta__"): meta = getattr(module, "__plugin_meta__") matcher.plugins[full_module_name] = meta - + type_str = "包" if is_pkg else "文件" print(f" [{type_str}] 成功{action}: {module_name}") except Exception as e: - print(f" {action if 'action' in locals() else '加载'}插件 {module_name} 失败: {e}") + print( + f" {action if 'action' in locals() else '加载'}插件 {module_name} 失败: {e}" + ) + + +class PluginDataManager: + """ + 用于管理插件产生的数据文件的类 + """ + + def __init__(self, plugin_name: str): + """ + 初始化插件数据管理器 + + :param plugin_name: 插件名称 + """ + self.plugin_name = plugin_name + self.data_file = os.path.join( + os.path.dirname(os.path.abspath(__file__)), + "..", + "plugins", + "data", + self.plugin_name + ".json", + ) + self.data = {} + self.load() + + def load(self): + """读取配置文件""" + if not os.path.exists(self.data_file): + with open(self.data_file, "w", encoding="utf-8") as f: + self.set(self.plugin_name, []) + try: + with open(self.data_file, "r", encoding="utf-8") as f: + self.data = json.load(f) + except json.JSONDecodeError: + self.data = {} + + def save(self): + """保存配置到文件""" + with open(self.data_file, "w", encoding="utf-8") as f: + json.dump(self.data, f, indent=2, ensure_ascii=False) + + def get(self, key, default=None): + """获取配置项""" + return self.data.get(key, default) + + def set(self, key, value): + """设置配置项""" + self.data[key] = value + self.save() + + def add(self, key, value): + """添加配置项""" + if key not in self.data: + self.data[key] = [] + self.data[key].append(value) + self.save() + + def remove(self, key): + """删除配置项""" + if key in self.data: + del self.data[key] + self.save() + + def clear(self): + """清空所有配置""" + self.data.clear() + self.save() + + def get_all(self): + return self.data.copy() diff --git a/plugins/admin.py b/plugins/admin.py new file mode 100644 index 0000000..8e1b0e6 --- /dev/null +++ b/plugins/admin.py @@ -0,0 +1,115 @@ +from core import PluginDataManager +from core.bot import Bot +from core.command_manager import matcher +from models import GroupMessageEvent + +__plugin_meta__ = { + "name": "admin", + "description": "机器人权限管理插件", + "usage": "/admin", +} + +data = PluginDataManager("admin") + + +@matcher.command("admin") +async def handle_permission(bot: Bot, event: GroupMessageEvent, args: list[str]): + if not args: + await event.reply( + "机器人权限管理插件指令:\n/admin list 列出所有权限\n/admin add member 添加群成员权限\n/admin remove member 删除群成员权限\n/admin add group <群号> 添加群权限\n/admin remove group <群号> 删除群权限\n/admin clear member 清空群成员权限\n/admin clear group 清空群权限\n/admin clear all 清空所有权限" + ) + return + + if str(event.user_id) not in data.get("members", []): + await event.reply("你没有权限使用此命令。") + return + if str(event.group_id) not in data.get("groups", []): + await event.reply("群聊不在权限中") + return + + action = args[0].lower() + + # ensure storage keys exist + members = data.get("members", []) or [] + groups = data.get("groups", []) or [] + + if action == "list": + msg_lines = ["当前权限列表:"] + msg_lines.append( + f"群成员权限 ({len(members)}): {', '.join(members) if members else '无'}" + ) + msg_lines.append( + f"群权限 ({len(groups)}): {', '.join(groups) if groups else '无'}" + ) + await event.reply("\n".join(msg_lines)) + return + + if action in ("add", "remove"): + if len(args) < 3: + await event.reply("参数错误,示例:/admin add member 123456") + return + + target = args[1].lower() + value = args[2] + + if target == "member": + # operate on members list + if action == "add": + if str(value) in members: + await event.reply(f"成员 {value} 已存在,无需重复添加。") + return + members.append(str(value)) + data.set("members", members) + await event.reply(f"已添加群成员权限:{value}") + return + else: # remove + if str(value) not in members: + await event.reply(f"成员 {value} 不在权限列表中。") + return + members = [m for m in members if m != str(value)] + data.set("members", members) + await event.reply(f"已移除群成员权限:{value}") + return + + if target == "group": + if action == "add": + if str(value) in groups: + await event.reply(f"群 {value} 已存在,无需重复添加。") + return + groups.append(str(value)) + data.set("groups", groups) + await event.reply(f"已添加群权限:{value}") + return + else: # remove + if str(value) not in groups: + await event.reply(f"群 {value} 不在权限列表中。") + return + groups = [g for g in groups if g != str(value)] + data.set("groups", groups) + await event.reply(f"已移除群权限:{value}") + return + + await event.reply("未知目标类型,请使用 member 或 group") + return + + if action == "clear": + if len(args) < 2: + await event.reply("参数错误,示例:/admin clear member") + return + target = args[1].lower() + if target == "member": + data.set("members", []) + await event.reply("已清空群成员权限。") + return + if target == "group": + data.set("groups", []) + await event.reply("已清空群权限。") + return + if target == "all": + data.clear() + await event.reply("已清空所有权限。") + return + await event.reply("未知清空目标,请使用 member/group/all") + return + + await event.reply("未知指令,使用 /admin 查看帮助") diff --git a/plugins/data/admin.json b/plugins/data/admin.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/plugins/data/admin.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/plugins/thpic.py b/plugins/thpic.py index 1d8c462..80e2cfd 100644 --- a/plugins/thpic.py +++ b/plugins/thpic.py @@ -5,16 +5,16 @@ thpic 插件 """ +from core.bot import Bot +from core.command_manager import matcher +from models import MessageEvent, MessageSegment + __plugin_meta__ = { "name": "thpic", "description": "来看看东方Project的图片吧!", "usage": "/thpic", } -from core.bot import Bot -from core.command_manager import matcher -from models import MessageEvent, MessageSegment - @matcher.command("thpic") async def handle_echo(bot: Bot, event: MessageEvent, args: list[str]):