diff --git a/README.md b/README.md index eec28ad..e6a9d25 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# NoneBot Plugin LitePerms 文档 +# NoneBot Plugin LitePerm 文档
SuggarChat Logo -

LitePerms

+

LitePerm

权限节点权限管理插件

@@ -58,13 +58,13 @@ 修改`pyproject.toml`,在`[tool.nonebot]`下的`plugins = ["nonebot_plugin_liteperm"]`添加插件 -## 配置 - -```toml -# 是否启用指令权限检查 -cmd_permission_checker=true -``` ## [指令文档](docs/commands.md) ## [API文档](docs/API.md) + +## 内置权限节点 + +| 权限节点 | 权限描述 | +| --- | --- | +| `liteperm.admin` | LitePerm管理员 | diff --git a/docs/commands.md b/docs/commands.md index e759268..ee8bd00 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -4,7 +4,7 @@ - **格式**:/lp - **功能**:显示插件帮助信息 -- **响应**:LP LitePerms 请输入参数: lp user lp group lp perm_group lp command +- **响应**:LP LitePerm 请输入参数: lp user lp group lp perm_group lp command ## 用户权限管理 diff --git a/pyproject.toml b/pyproject.toml index 06e783c..57f012b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "nonebot_plugin_liteperm" -version = "0.0.1.post3" +version = "0.0.2" description = "基于权限节点/权限组/特殊权限的Nonebot权限管理插件。" authors = [ { name = "JohnRichard4096", email = "windowserror@163.com" }, @@ -14,14 +14,10 @@ dependencies = [ "tomli>=2.2.1", "tomli-w>=1.2.0", ] -requires-python = ">=3.9, <4.0" +requires-python = ">=3.10, <4.0" readme = "README.md" license = { text = "GPL-3.0-or-later" } keywords = ['nonebot'] -[build-system] -requires = ['pdm-backend'] -build-backend = "pdm.backend" - [tool.pdm] distribution = true diff --git a/src/nonebot_plugin_liteperm/API/admin.py b/src/nonebot_plugin_liteperm/API/admin.py index 76b3856..2021913 100644 --- a/src/nonebot_plugin_liteperm/API/admin.py +++ b/src/nonebot_plugin_liteperm/API/admin.py @@ -1,13 +1,10 @@ -import os - -from dotenv import load_dotenv +from nonebot import get_driver from nonebot.adapters.onebot.v11 import Event from ..config import UserData, data_manager from ..nodelib import Permissions -load_dotenv() -ENV_ADMINS = os.getenv("LP_ADMINS", []) +ENV_ADMINS = get_driver().config.superusers async def is_lp_admin(event: Event) -> bool: @@ -16,6 +13,7 @@ async def is_lp_admin(event: Event) -> bool: """ user_id = event.get_user_id() user_data: UserData = data_manager.get_user_data(user_id) - return user_id in ENV_ADMINS or Permissions(user_data.permissions).check_permission( - "lp.admin" - ) + return ( + user_id in ENV_ADMINS + or Permissions(user_data.permissions).check_permission("lp.admin") + ) and data_manager.config.enable diff --git a/src/nonebot_plugin_liteperm/command_manager.py b/src/nonebot_plugin_liteperm/command_manager.py index 5aef112..6764fd2 100644 --- a/src/nonebot_plugin_liteperm/command_manager.py +++ b/src/nonebot_plugin_liteperm/command_manager.py @@ -2,5 +2,5 @@ from nonebot.rule import to_me command = CommandGroup( - ("lp", "LP", "LitePerms"), priority=10, block=True, rule=to_me(), prefix_aliases=True + ("lp", "LP", "LitePerm"), priority=10, block=True, rule=to_me(), prefix_aliases=True ) diff --git a/src/nonebot_plugin_liteperm/commands/lp_command.py b/src/nonebot_plugin_liteperm/commands/lp_command.py deleted file mode 100644 index 5e2d23f..0000000 --- a/src/nonebot_plugin_liteperm/commands/lp_command.py +++ /dev/null @@ -1,95 +0,0 @@ -""" -import asyncio -from typing import Any, override - -from nonebot.adapters.onebot.v11 import MessageEvent -from nonebot.matcher import Matcher -from nonebot.params import Depends - -from ..API.admin import is_lp_admin -from ..config import CommandConfig, data_manager -from .cmd_utils import parse_command -from .main import PermissionHandler, command - - -class PermissionOperation(PermissionHandler): - @override - async def execute( - self, command: str, operation: str, node: str, value: str - ) -> tuple[str, dict[str, Any]]: - result = " " - command_data = data_manager.get_command_settings() - if operation == "set": - command_data.commands[command][node] = ( - True if value.lower() == "true" else False - ) - return "✅ 操作成功", command_data.model_dump() - elif operation == "del": - if command in command_data.commands: - if node in command_data.commands[command]: - del command_data.commands[command][node] - return "✅ 操作成功", command_data.model_dump() - else: - return "❌ 节点不存在", {} - return result, command_data.model_dump() - - -class DelPermissionSetting(PermissionHandler): - async def execute( - self, command: str, operation: str, node: str, value: str - ) -> tuple[str, dict[str, Any]]: - result = "❌ 操作失败" - command_data = data_manager.get_command_settings() - if operation == "del" and command in command_data.commands: - del command_data.commands[command] - result = "✅ 操作成功" - return result, command_data.model_dump() - - -class ListHandler(PermissionHandler): - async def execute( - self, user_id: str, operation: str, command: str, _: str - ) -> tuple[str, dict[str, Any]]: - result = "❌ 操作失败" - command_data = data_manager.get_command_settings() - if operation == "list": - result = "已设置的命令:" - for command in command_data.commands: - result += f"\n{command} {''.join(f'{node} ,' for node, _ in command_data.commands[command].items())}" - return result, {} - - -def get_handler( - action_type: str, -) -> PermissionHandler | None: - handlers: dict[str, PermissionHandler] = { - "set_permission": PermissionOperation(), - "command": DelPermissionSetting(), - "list": ListHandler(), - } - return handlers.get(action_type) - - -@command.command("command", permission=is_lp_admin).handle() -async def lp_user( - event: MessageEvent, - matcher: Matcher, - params: tuple[str, str, str, str, str] = Depends(parse_command), -): - command_name, action_type, operation, target, value = params - handler = get_handler(action_type) - if handler is None: - await matcher.finish("❌ 未知操作类型") - try: - result, data = await handler.execute(command_name, operation, target, value) - except ValueError as e: - result = f"❌ 操作失败:{e!s}" - finally: - lock = asyncio.locks.Lock() - async with lock: - if data: - data_manager.save_command_settings(CommandConfig(**data)) - - await matcher.finish(result) - -""" diff --git a/src/nonebot_plugin_liteperm/commands/main.py b/src/nonebot_plugin_liteperm/commands/main.py index e8c15be..ea386a2 100644 --- a/src/nonebot_plugin_liteperm/commands/main.py +++ b/src/nonebot_plugin_liteperm/commands/main.py @@ -19,8 +19,6 @@ async def execute( async def lp(event: MessageEvent, matcher: Matcher, args: Message = CommandArg()): args_list = args.extract_plain_text().strip().split() if not args_list: - lp_0_help = ( - "LP LitePerms\n请输入参数\nlp user\nlp chat_group\nlp perm_group\nlp command\n" - ) + lp_0_help = "LP LitePerm\n请输入参数\nlp user\nlp chat_group\nlp perm_group\nlp command\n" await matcher.finish(lp_0_help) diff --git a/src/nonebot_plugin_liteperm/config.py b/src/nonebot_plugin_liteperm/config.py index 4820a2d..2a7049d 100644 --- a/src/nonebot_plugin_liteperm/config.py +++ b/src/nonebot_plugin_liteperm/config.py @@ -15,15 +15,7 @@ os.makedirs(config_dir, exist_ok=True) -class BasicDataModel(BaseModel, extra="allow"): - def __getattr__(self, item) -> str: - if item in self.__dict__: - return self.__dict__[item] - if self.__pydantic_extra__ and item in self.__pydantic_extra__: - return self.__pydantic_extra__[item] - raise AttributeError( - f"'{self.__class__.__name__}' object has no attribute '{item}'" - ) +class BasicDataModel(BaseModel, extra="allow"): ... class UserData(BasicDataModel): @@ -40,17 +32,8 @@ class PermissionGroupData(BasicDataModel): permissions: dict[str, str | dict | bool] = {} -""" -class CommandConfig(BasicDataModel): - commands: dict[str, dict[str, bool]] = {"lp.user": {"lp.admin": True}} -""" - - class Config(BasicDataModel): - cmd_permission_checker: bool = Field( - default=True, - description="是否开启命令权限检查", - ) + enable: bool = Field(default=True, description="是否启用插件") def save_to_toml(self, path: Path): """保存配置到 TOML 文件""" diff --git a/src/nonebot_plugin_liteperm/hooks.py b/src/nonebot_plugin_liteperm/hooks.py deleted file mode 100644 index cde770a..0000000 --- a/src/nonebot_plugin_liteperm/hooks.py +++ /dev/null @@ -1,127 +0,0 @@ -""" -import nonebot.matcher as nbm -from nonebot import get_driver, logger -from nonebot.adapters import Event -from nonebot.exception import IgnoredException, NoneBotException -from nonebot.matcher import Matcher -from nonebot.message import event_preprocessor - -from .config import PermissionGroupData, data_manager -from .nodelib import Permissions -from .utils import GroupEvent - -driver = get_driver() -command_starts = driver.config.command_start # 获取配置的命令起始符(如 ["/", "!"]) - - -@event_preprocessor -async def check_on_command(event: Event): - # 获取消息文本并去除首尾空格 - msg = event.get_message().extract_plain_text().strip() - user_id = event.get_user_id() - if isinstance(event, GroupEvent): - group_id: int | None = event.group_id - else: - group_id: int | None = None - # 遍历所有可能的命令起始符 - for start in command_starts: - if msg.startswith(start): - cmd_part = msg[len(start) :].split(maxsplit=1)[0] - - for priority_group in nbm.matchers.values(): - for matcher_cls in priority_group: - try: - # 检查是否是on_command创建的Matcher - if not ( - matcher_cls.type == "message" - and any( - rule.call.__name__ == "_check_command" - for rule in matcher_cls.rule.checkers - ) - ): - continue - - # 从规则中提取命令参数 - command_rule = next( - rule - for rule in matcher_cls.rule.checkers - if rule.call.__name__ == "_check_command" - ) - commands = command_rule.call.args[0] - - # 处理命令格式 - all_commands = { - cmd if isinstance(cmd, str) else cmd[0] for cmd in commands - } - - if cmd_part in all_commands: - if not data_manager.config.cmd_permission_checker: - return - cmd_data = data_manager.get_command_settings() - if cmd_part in cmd_data.commands: - user_data = data_manager.get_user_data(user_id) - user_permissions = Permissions(user_data.permissions) - user_permission_groups = user_data.permission_groups - for permission in cmd_data.commands[cmd_part].keys(): - for group in user_permission_groups: - perm_group_data = ( - data_manager.get_permission_group_data( - group - ) - ) - if perm_group_data is None: - user_permission_groups.remove(group) - data_manager.save_user_data( - user_id, user_data.model_dump() - ) - elif Permissions( - perm_group_data.permissions - ).check_permission(permission): - return - if user_permissions.check_permission(permission): - return - elif group_id is not None: - group_data = data_manager.get_group_data( - str(group_id) - ) - group_permissions = Permissions( - group_data.permissions - ) - if group_permissions.check_permission( - permission - ): - return - group_perm_groups = group_data.permission_groups - for group_perm_group in group_perm_groups: - data: PermissionGroupData | None = ( - data_manager.get_permission_group_data( - group_perm_group - ) - ) - if data is None: - group_data.permission_groups.remove( - group_perm_group - ) - data_manager.save_group_data( - str(group_id), - group_data.model_dump(), - ) - elif Permissions( - data.permissions - ).check_permission(permission): - return - raise IgnoredException( - f"Permission {permission} denied" - ) - else: - raise IgnoredException( - f"Permission {permission} denied" - ) - except (StopIteration, AttributeError): - continue - except NoneBotException as e: - raise e - except Exception as e: - logger.error(f"Matcher检查错误: {e}") - -""" diff --git a/src/nonebot_plugin_liteperm/on_init.py b/src/nonebot_plugin_liteperm/on_init.py index cf06887..2154c31 100644 --- a/src/nonebot_plugin_liteperm/on_init.py +++ b/src/nonebot_plugin_liteperm/on_init.py @@ -1,39 +1,23 @@ -import contextlib +from importlib.metadata import PackageNotFoundError +from importlib.metadata import version as get_version from nonebot import get_driver from .config import data_manager -__VERSION__ = "v1.00" banner_template = """\033[34m▗▖ ▗▄▄▖ -▐▌ ▐▌ ▐▌ \033[96mLitePerms\033[34m \033[1;4;34mV{version}\033[0m\033[34m +▐▌ ▐▌ ▐▌ \033[96mLitePerm\033[34m \033[1;4;34mV{version}\033[0m\033[34m ▐▌ ▐▛▀▘ is initializing... ▐▙▄▄▖▐▌\033[0m""" @get_driver().on_startup async def load_config(): - import asyncio - import subprocess - import sys version = "unknown" try: - process = await asyncio.create_subprocess_exec( - sys.executable, - "-m", - "pip", - "show", - "nonebot-plugin-suggarchat", - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE, - ) - stdout, _ = await process.communicate() - with contextlib.suppress(IndexError): - version = stdout.decode("utf-8").split("\n")[1].split(": ")[1] - except subprocess.CalledProcessError: - pass - except Exception: + version = get_version("nonebot-plugin-liteperm") + except PackageNotFoundError: pass print(banner_template.format(version=version))