mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-09-28 16:20:56 +08:00
bugfix:修复插件商店插件卸载问题,显示问题,移除权限检查多余部分 (#2124)
* bugfix:修复插件商店插件卸载问题,显示问题,移除权限检查多余部分 * bugfix:修复撤回问题,插件商店显示问题
This commit is contained in:
@@ -11,7 +11,6 @@ from zhenxun.utils.utils import get_entity_ids
|
|||||||
|
|
||||||
from .config import LOGGER_COMMAND, WARNING_THRESHOLD
|
from .config import LOGGER_COMMAND, WARNING_THRESHOLD
|
||||||
from .exception import SkipPluginException
|
from .exception import SkipPluginException
|
||||||
from .utils import send_message
|
|
||||||
|
|
||||||
|
|
||||||
async def auth_admin(
|
async def auth_admin(
|
||||||
@@ -51,29 +50,24 @@ async def auth_admin(
|
|||||||
user_level = max(user_level, group_users.user_level)
|
user_level = max(user_level, group_users.user_level)
|
||||||
|
|
||||||
if user_level < plugin.admin_level:
|
if user_level < plugin.admin_level:
|
||||||
await send_message(
|
raise SkipPluginException(
|
||||||
session,
|
f"{plugin.name}({plugin.module}) 管理员权限不足...",
|
||||||
[
|
tip_message=[
|
||||||
At(flag="user", target=session.user.id),
|
At(flag="user", target=session.user.id),
|
||||||
f"你的权限不足喔,该功能需要的权限等级: {plugin.admin_level}",
|
f"你的权限不足喔,该功能需要的权限等级: {plugin.admin_level}",
|
||||||
],
|
],
|
||||||
entity.user_id,
|
tip_check_tag=entity.user_id,
|
||||||
background=True,
|
tip_background=True,
|
||||||
)
|
|
||||||
|
|
||||||
raise SkipPluginException(
|
|
||||||
f"{plugin.name}({plugin.module}) 管理员权限不足..."
|
|
||||||
)
|
)
|
||||||
elif global_user:
|
elif global_user:
|
||||||
if global_user.user_level < plugin.admin_level:
|
if global_user.user_level < plugin.admin_level:
|
||||||
await send_message(
|
|
||||||
session,
|
|
||||||
f"你的权限不足喔,该功能需要的权限等级: {plugin.admin_level}",
|
|
||||||
background=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
raise SkipPluginException(
|
raise SkipPluginException(
|
||||||
f"{plugin.name}({plugin.module}) 管理员权限不足..."
|
f"{plugin.name}({plugin.module}) 管理员权限不足...",
|
||||||
|
tip_message=(
|
||||||
|
f"你的权限不足喔,该功能需要的权限等级: "
|
||||||
|
f"{plugin.admin_level}"
|
||||||
|
),
|
||||||
|
tip_background=True,
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
# 记录执行时间
|
# 记录执行时间
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from nonebot.adapters import Bot
|
|
||||||
from nonebot.matcher import Matcher
|
from nonebot.matcher import Matcher
|
||||||
from nonebot_plugin_alconna import At
|
from nonebot_plugin_alconna import At
|
||||||
from nonebot_plugin_uninfo import Uninfo
|
from nonebot_plugin_uninfo import Uninfo
|
||||||
@@ -18,7 +17,7 @@ from zhenxun.utils.utils import EntityIDs, get_entity_ids
|
|||||||
|
|
||||||
from .config import LOGGER_COMMAND, WARNING_THRESHOLD
|
from .config import LOGGER_COMMAND, WARNING_THRESHOLD
|
||||||
from .exception import SkipPluginException
|
from .exception import SkipPluginException
|
||||||
from .utils import freq, send_message
|
from .utils import freq
|
||||||
|
|
||||||
Config.add_plugin_config(
|
Config.add_plugin_config(
|
||||||
"hook",
|
"hook",
|
||||||
@@ -189,20 +188,15 @@ async def user_handle(plugin: PluginInfo, entity: EntityIDs, session: Uninfo) ->
|
|||||||
and ban_result
|
and ban_result
|
||||||
and freq.is_send_limit_message(plugin, entity.user_id, False)
|
and freq.is_send_limit_message(plugin, entity.user_id, False)
|
||||||
):
|
):
|
||||||
try:
|
raise SkipPluginException(
|
||||||
await asyncio.wait_for(
|
"用户处于黑名单中...",
|
||||||
send_message(
|
tip_message=[
|
||||||
session,
|
At(flag="user", target=entity.user_id),
|
||||||
[
|
f"{ban_result}\n在..在 {time_str} 后才会理你喔",
|
||||||
At(flag="user", target=entity.user_id),
|
],
|
||||||
f"{ban_result}\n在..在 {time_str} 后才会理你喔",
|
tip_check_tag=entity.user_id,
|
||||||
],
|
tip_timeout=DB_TIMEOUT_SECONDS,
|
||||||
entity.user_id,
|
)
|
||||||
),
|
|
||||||
timeout=DB_TIMEOUT_SECONDS,
|
|
||||||
)
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
logger.error(f"发送消息超时: {entity.user_id}", LOGGER_COMMAND)
|
|
||||||
raise SkipPluginException("用户处于黑名单中...")
|
raise SkipPluginException("用户处于黑名单中...")
|
||||||
finally:
|
finally:
|
||||||
# 记录执行时间
|
# 记录执行时间
|
||||||
@@ -217,16 +211,16 @@ async def user_handle(plugin: PluginInfo, entity: EntityIDs, session: Uninfo) ->
|
|||||||
|
|
||||||
async def auth_ban(
|
async def auth_ban(
|
||||||
matcher: Matcher,
|
matcher: Matcher,
|
||||||
bot: Bot,
|
|
||||||
session: Uninfo,
|
session: Uninfo,
|
||||||
plugin: PluginInfo,
|
plugin: PluginInfo,
|
||||||
|
*,
|
||||||
entity: EntityIDs | None = None,
|
entity: EntityIDs | None = None,
|
||||||
|
is_superuser: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""权限检查 - ban 检查
|
"""权限检查 - ban 检查
|
||||||
|
|
||||||
参数:
|
参数:
|
||||||
matcher: Matcher
|
matcher: Matcher
|
||||||
bot: Bot
|
|
||||||
session: Uninfo
|
session: Uninfo
|
||||||
"""
|
"""
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
@@ -237,7 +231,7 @@ async def auth_ban(
|
|||||||
return
|
return
|
||||||
if entity is None:
|
if entity is None:
|
||||||
entity = get_entity_ids(session)
|
entity = get_entity_ids(session)
|
||||||
if entity.user_id in bot.config.superusers:
|
if is_superuser:
|
||||||
return
|
return
|
||||||
if entity.group_id:
|
if entity.group_id:
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ from zhenxun.services.log import logger
|
|||||||
|
|
||||||
from .config import LOGGER_COMMAND, WARNING_THRESHOLD
|
from .config import LOGGER_COMMAND, WARNING_THRESHOLD
|
||||||
from .exception import SkipPluginException
|
from .exception import SkipPluginException
|
||||||
from .utils import send_message
|
|
||||||
|
|
||||||
DEFAULT_GOLD = 100
|
DEFAULT_GOLD = 100
|
||||||
|
|
||||||
@@ -32,8 +31,10 @@ async def auth_cost(
|
|||||||
user_gold = user.gold if user else DEFAULT_GOLD
|
user_gold = user.gold if user else DEFAULT_GOLD
|
||||||
if user_gold < plugin.cost_gold:
|
if user_gold < plugin.cost_gold:
|
||||||
"""插件消耗金币不足"""
|
"""插件消耗金币不足"""
|
||||||
await send_message(session, f"金币不足..该功能需要{plugin.cost_gold}金币..")
|
raise SkipPluginException(
|
||||||
raise SkipPluginException(f"{plugin.name}({plugin.module}) 金币限制...")
|
f"{plugin.name}({plugin.module}) 金币限制...",
|
||||||
|
tip_message=f"金币不足..该功能需要{plugin.cost_gold}金币..",
|
||||||
|
)
|
||||||
return plugin.cost_gold
|
return plugin.cost_gold
|
||||||
finally:
|
finally:
|
||||||
# 记录执行时间
|
# 记录执行时间
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from zhenxun.utils.enum import BlockType
|
|||||||
|
|
||||||
from .config import LOGGER_COMMAND, WARNING_THRESHOLD
|
from .config import LOGGER_COMMAND, WARNING_THRESHOLD
|
||||||
from .exception import IsSuperuserException, SkipPluginException
|
from .exception import IsSuperuserException, SkipPluginException
|
||||||
from .utils import freq, is_poke, send_message
|
from .utils import freq, is_poke
|
||||||
|
|
||||||
|
|
||||||
def _get_group_block_sets(
|
def _get_group_block_sets(
|
||||||
@@ -59,46 +59,41 @@ class GroupCheck:
|
|||||||
self.group_data
|
self.group_data
|
||||||
and self.plugin.module in self.superuser_block_plugin_set
|
and self.plugin.module in self.superuser_block_plugin_set
|
||||||
):
|
):
|
||||||
if freq.is_send_limit_message(
|
should_tip = freq.is_send_limit_message(
|
||||||
self.plugin, self.group_id, self.is_poke
|
self.plugin, self.group_id, self.is_poke
|
||||||
):
|
)
|
||||||
await send_message(
|
|
||||||
self.session,
|
|
||||||
"超级管理员禁用了该群此功能...",
|
|
||||||
self.group_id,
|
|
||||||
background=True,
|
|
||||||
)
|
|
||||||
raise SkipPluginException(
|
raise SkipPluginException(
|
||||||
f"{self.plugin.name}({self.plugin.module})"
|
f"{self.plugin.name}({self.plugin.module})"
|
||||||
f" 超级管理员禁用了该群此功能..."
|
f" 超级管理员禁用了该群此功能...",
|
||||||
|
tip_message=(
|
||||||
|
"超级管理员禁用了该群此功能..." if should_tip else None
|
||||||
|
),
|
||||||
|
tip_check_tag=self.group_id if should_tip else None,
|
||||||
|
tip_background=should_tip,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 检查普通禁用
|
# 检查普通禁用
|
||||||
if self.group_data and self.plugin.module in self.block_plugin_set:
|
if self.group_data and self.plugin.module in self.block_plugin_set:
|
||||||
if freq.is_send_limit_message(
|
should_tip = freq.is_send_limit_message(
|
||||||
self.plugin, self.group_id, self.is_poke
|
self.plugin, self.group_id, self.is_poke
|
||||||
):
|
)
|
||||||
await send_message(
|
|
||||||
self.session,
|
|
||||||
"该群未开启此功能...",
|
|
||||||
self.group_id,
|
|
||||||
background=True,
|
|
||||||
)
|
|
||||||
raise SkipPluginException(
|
raise SkipPluginException(
|
||||||
f"{self.plugin.name}({self.plugin.module}) 未开启此功能..."
|
f"{self.plugin.name}({self.plugin.module}) 未开启此功能...",
|
||||||
|
tip_message="该群未开启此功能..." if should_tip else None,
|
||||||
|
tip_check_tag=self.group_id if should_tip else None,
|
||||||
|
tip_background=should_tip,
|
||||||
)
|
)
|
||||||
|
|
||||||
# 检查全局禁用
|
# 检查全局禁用
|
||||||
if self.plugin.block_type == BlockType.GROUP:
|
if self.plugin.block_type == BlockType.GROUP:
|
||||||
if freq.is_send_limit_message(self.plugin, self.group_id, self.is_poke):
|
should_tip = freq.is_send_limit_message(
|
||||||
await send_message(
|
self.plugin, self.group_id, self.is_poke
|
||||||
self.session,
|
)
|
||||||
"该功能在群组中已被禁用...",
|
|
||||||
self.group_id,
|
|
||||||
background=True,
|
|
||||||
)
|
|
||||||
raise SkipPluginException(
|
raise SkipPluginException(
|
||||||
f"{self.plugin.name}({self.plugin.module})该插件在群组中已被禁用..."
|
f"{self.plugin.name}({self.plugin.module})该插件在群组中已被禁用...",
|
||||||
|
tip_message="该功能在群组中已被禁用..." if should_tip else None,
|
||||||
|
tip_check_tag=self.group_id if should_tip else None,
|
||||||
|
tip_background=should_tip,
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
# 记录执行时间
|
# 记录执行时间
|
||||||
@@ -131,14 +126,14 @@ class PluginCheck:
|
|||||||
IgnoredException: 忽略插件
|
IgnoredException: 忽略插件
|
||||||
"""
|
"""
|
||||||
if plugin.block_type == BlockType.PRIVATE:
|
if plugin.block_type == BlockType.PRIVATE:
|
||||||
if freq.is_send_limit_message(plugin, self.session.user.id, self.is_poke):
|
should_tip = freq.is_send_limit_message(
|
||||||
await send_message(
|
plugin, self.session.user.id, self.is_poke
|
||||||
self.session,
|
)
|
||||||
"该功能在私聊中已被禁用...",
|
|
||||||
background=True,
|
|
||||||
)
|
|
||||||
raise SkipPluginException(
|
raise SkipPluginException(
|
||||||
f"{plugin.name}({plugin.module}) 该插件在私聊中已被禁用..."
|
f"{plugin.name}({plugin.module}) 该插件在私聊中已被禁用...",
|
||||||
|
tip_message="该功能在私聊中已被禁用..." if should_tip else None,
|
||||||
|
tip_check_tag=self.session.user.id if should_tip else None,
|
||||||
|
tip_background=should_tip,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def check_global(self, plugin: PluginInfo):
|
async def check_global(self, plugin: PluginInfo):
|
||||||
@@ -159,15 +154,12 @@ class PluginCheck:
|
|||||||
raise IsSuperuserException()
|
raise IsSuperuserException()
|
||||||
|
|
||||||
sid = self.group_id or self.session.user.id
|
sid = self.group_id or self.session.user.id
|
||||||
if freq.is_send_limit_message(plugin, sid, self.is_poke):
|
should_tip = freq.is_send_limit_message(plugin, sid, self.is_poke)
|
||||||
await send_message(
|
|
||||||
self.session,
|
|
||||||
"全局未开启此功能...",
|
|
||||||
sid,
|
|
||||||
background=True,
|
|
||||||
)
|
|
||||||
raise SkipPluginException(
|
raise SkipPluginException(
|
||||||
f"{plugin.name}({plugin.module}) 全局未开启此功能..."
|
f"{plugin.name}({plugin.module}) 全局未开启此功能...",
|
||||||
|
tip_message="全局未开启此功能..." if should_tip else None,
|
||||||
|
tip_check_tag=sid if should_tip else None,
|
||||||
|
tip_background=should_tip,
|
||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
# 记录执行时间
|
# 记录执行时间
|
||||||
|
|||||||
@@ -3,9 +3,21 @@ class IsSuperuserException(Exception):
|
|||||||
|
|
||||||
|
|
||||||
class SkipPluginException(Exception):
|
class SkipPluginException(Exception):
|
||||||
def __init__(self, info: str, *args: object) -> None:
|
def __init__(
|
||||||
|
self,
|
||||||
|
info: str,
|
||||||
|
*args: object,
|
||||||
|
tip_message: list | str | None = None,
|
||||||
|
tip_check_tag: str | None = None,
|
||||||
|
tip_background: bool = False,
|
||||||
|
tip_timeout: float | None = None,
|
||||||
|
) -> None:
|
||||||
super().__init__(*args)
|
super().__init__(*args)
|
||||||
self.info = info
|
self.info = info
|
||||||
|
self.tip_message = tip_message
|
||||||
|
self.tip_check_tag = tip_check_tag
|
||||||
|
self.tip_background = tip_background
|
||||||
|
self.tip_timeout = tip_timeout
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return self.info
|
return self.info
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ from zhenxun.utils.platform import PlatformUtils
|
|||||||
from zhenxun.utils.utils import get_entity_ids
|
from zhenxun.utils.utils import get_entity_ids
|
||||||
|
|
||||||
from .auth.auth_admin import auth_admin
|
from .auth.auth_admin import auth_admin
|
||||||
from .auth.auth_ban import auth_ban, is_ban
|
from .auth.auth_ban import auth_ban
|
||||||
from .auth.auth_bot import auth_bot
|
from .auth.auth_bot import auth_bot
|
||||||
from .auth.auth_cost import auth_cost
|
from .auth.auth_cost import auth_cost
|
||||||
from .auth.auth_group import auth_group
|
from .auth.auth_group import auth_group
|
||||||
@@ -49,6 +49,7 @@ from .auth.exception import (
|
|||||||
PermissionExemption,
|
PermissionExemption,
|
||||||
SkipPluginException,
|
SkipPluginException,
|
||||||
)
|
)
|
||||||
|
from .auth.utils import send_message
|
||||||
|
|
||||||
AUTH_HOOKS_CONCURRENCY_LIMIT = 5
|
AUTH_HOOKS_CONCURRENCY_LIMIT = 5
|
||||||
AUTH_DB_CONCURRENCY_LIMIT = 6
|
AUTH_DB_CONCURRENCY_LIMIT = 6
|
||||||
@@ -461,14 +462,26 @@ def _matcher_route_cache_key(event: Event) -> str:
|
|||||||
|
|
||||||
|
|
||||||
def _event_plain_text(event: Event) -> str:
|
def _event_plain_text(event: Event) -> str:
|
||||||
|
def _normalize(text: str) -> str:
|
||||||
|
normalized = text.strip()
|
||||||
|
if not normalized:
|
||||||
|
return ""
|
||||||
|
# strip leading placeholders like "[reply:id=10004]撤回"
|
||||||
|
normalized = re.sub(
|
||||||
|
r"^(?:\s*(?:\[[^\]]*]|\<[^>]*>))+\s*",
|
||||||
|
"",
|
||||||
|
normalized,
|
||||||
|
)
|
||||||
|
return normalized.strip()
|
||||||
|
|
||||||
with contextlib.suppress(Exception):
|
with contextlib.suppress(Exception):
|
||||||
# Use raw_message if available (OneBot v11) to get the original text
|
# Use raw_message if available (OneBot v11) to get the original text
|
||||||
# before nickname stripping. This ensures command matching works correctly
|
# before nickname stripping. This ensures command matching works correctly
|
||||||
# for commands like "真寻日报" when "真寻" is a bot nickname.
|
# for commands like "真寻日报" when "真寻" is a bot nickname.
|
||||||
raw = getattr(event, "raw_message", None)
|
raw = getattr(event, "raw_message", None)
|
||||||
if isinstance(raw, str) and raw:
|
if isinstance(raw, str) and raw:
|
||||||
return raw.strip()
|
return _normalize(raw)
|
||||||
return (event.get_plaintext() or "").strip()
|
return _normalize(event.get_plaintext() or "")
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
@@ -1028,12 +1041,6 @@ async def _fetch_user_readonly(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _fetch_plugin(plugin_dao: DataAccess, module: str) -> PluginInfo | None:
|
|
||||||
return await with_timeout(
|
|
||||||
plugin_dao.safe_get_or_none(module=module), name="get_plugin"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def get_plugin_and_user(
|
async def get_plugin_and_user(
|
||||||
module: str,
|
module: str,
|
||||||
user_id: str,
|
user_id: str,
|
||||||
@@ -1078,7 +1085,11 @@ async def get_plugin_and_user(
|
|||||||
|
|
||||||
|
|
||||||
async def get_plugin_cost(
|
async def get_plugin_cost(
|
||||||
bot: Bot, user: UserConsole | None, plugin: PluginInfo, session: Uninfo
|
user: UserConsole | None,
|
||||||
|
plugin: PluginInfo,
|
||||||
|
session: Uninfo,
|
||||||
|
*,
|
||||||
|
is_superuser: bool = False,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""获取插件费用
|
"""获取插件费用
|
||||||
|
|
||||||
@@ -1096,7 +1107,7 @@ async def get_plugin_cost(
|
|||||||
int: 调用插件金币费用
|
int: 调用插件金币费用
|
||||||
"""
|
"""
|
||||||
cost_gold = await with_timeout(auth_cost(user, plugin, session), name="auth_cost")
|
cost_gold = await with_timeout(auth_cost(user, plugin, session), name="auth_cost")
|
||||||
if session.user.id in bot.config.superusers:
|
if is_superuser:
|
||||||
if plugin.plugin_type == PluginType.SUPERUSER:
|
if plugin.plugin_type == PluginType.SUPERUSER:
|
||||||
raise IsSuperuserException()
|
raise IsSuperuserException()
|
||||||
if not plugin.limit_superuser:
|
if not plugin.limit_superuser:
|
||||||
@@ -1184,30 +1195,6 @@ async def _leave_hooks_section():
|
|||||||
HOOKS_ACTIVE_COUNT = max(HOOKS_ACTIVE_COUNT - 1, 0)
|
HOOKS_ACTIVE_COUNT = max(HOOKS_ACTIVE_COUNT - 1, 0)
|
||||||
|
|
||||||
|
|
||||||
async def auth_ban_fast(
|
|
||||||
matcher: Matcher, event: Event, bot: Bot, session: Uninfo
|
|
||||||
) -> None:
|
|
||||||
"""快速 ban 检测(仅使用内存缓存),用于前置快速裁决。"""
|
|
||||||
entity = get_entity_ids(session)
|
|
||||||
event_cache = _get_event_cache(event, session, entity)
|
|
||||||
if event_cache is not None and event_cache.get("ban_state") is True:
|
|
||||||
raise SkipPluginException("user or group banned (cached)")
|
|
||||||
if entity.user_id in bot.config.superusers:
|
|
||||||
if event_cache is not None:
|
|
||||||
event_cache["ban_state"] = False
|
|
||||||
return
|
|
||||||
if entity.group_id and await is_ban(None, entity.group_id):
|
|
||||||
if event_cache is not None:
|
|
||||||
event_cache["ban_state"] = True
|
|
||||||
raise SkipPluginException("group banned (fast)")
|
|
||||||
if entity.user_id and await is_ban(entity.user_id, entity.group_id):
|
|
||||||
if event_cache is not None:
|
|
||||||
event_cache["ban_state"] = True
|
|
||||||
raise SkipPluginException("user banned (fast)")
|
|
||||||
if event_cache is not None:
|
|
||||||
event_cache["ban_state"] = False
|
|
||||||
|
|
||||||
|
|
||||||
async def route_precheck(
|
async def route_precheck(
|
||||||
matcher: Matcher,
|
matcher: Matcher,
|
||||||
event: Event,
|
event: Event,
|
||||||
@@ -1243,60 +1230,6 @@ async def route_precheck(
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
async def auth_precheck(
|
|
||||||
matcher: Matcher,
|
|
||||||
event: Event,
|
|
||||||
bot: Bot,
|
|
||||||
session: Uninfo,
|
|
||||||
message: UniMsg,
|
|
||||||
) -> None:
|
|
||||||
"""轻量前置检查:命令路由 + 必要管理员权限。"""
|
|
||||||
module = matcher.plugin_name or ""
|
|
||||||
if not module:
|
|
||||||
return
|
|
||||||
if _is_hidden_plugin(matcher):
|
|
||||||
return
|
|
||||||
entity = get_entity_ids(session)
|
|
||||||
|
|
||||||
if session.user.id in bot.config.superusers:
|
|
||||||
return
|
|
||||||
|
|
||||||
plugin = cast(PluginInfo | None, await PluginInfoMemoryCache.get_by_module(module))
|
|
||||||
if not plugin:
|
|
||||||
return
|
|
||||||
|
|
||||||
if plugin.plugin_type == PluginType.SUPERUSER:
|
|
||||||
raise SkipPluginException("超级管理员权限不足...")
|
|
||||||
|
|
||||||
if _needs_admin_check(plugin):
|
|
||||||
await LevelUserMemoryCache.ensure_fresh()
|
|
||||||
levels = await LevelUserMemoryCache.get_levels(session.user.id, entity.group_id)
|
|
||||||
await auth_admin(plugin, session, cached_levels=levels)
|
|
||||||
# 缓存 admin 检查结果到 event_cache,避免 auth() 重复执行
|
|
||||||
event_cache = _get_event_cache(event, session, entity)
|
|
||||||
if event_cache is not None:
|
|
||||||
event_cache["admin_levels"] = levels
|
|
||||||
event_cache["admin_timeout"] = False
|
|
||||||
event_cache["admin_precheck_done"] = True
|
|
||||||
|
|
||||||
|
|
||||||
async def _call_auth_ban_compat(
|
|
||||||
matcher: Matcher,
|
|
||||||
bot: Bot,
|
|
||||||
session: Uninfo,
|
|
||||||
plugin: PluginInfo,
|
|
||||||
*,
|
|
||||||
entity,
|
|
||||||
) -> None:
|
|
||||||
"""兼容旧签名 auth_ban(matcher, bot, session, plugin)。"""
|
|
||||||
try:
|
|
||||||
await auth_ban(matcher, bot, session, plugin, entity=entity)
|
|
||||||
except TypeError as exc:
|
|
||||||
if "unexpected keyword argument 'entity'" not in str(exc):
|
|
||||||
raise
|
|
||||||
await auth_ban(matcher, bot, session, plugin)
|
|
||||||
|
|
||||||
|
|
||||||
async def auth(
|
async def auth(
|
||||||
matcher: Matcher,
|
matcher: Matcher,
|
||||||
event: Event,
|
event: Event,
|
||||||
@@ -1309,7 +1242,7 @@ async def auth(
|
|||||||
event_cache: dict | None = None,
|
event_cache: dict | None = None,
|
||||||
text: str | None = None,
|
text: str | None = None,
|
||||||
route_modules: set[str] | None = None,
|
route_modules: set[str] | None = None,
|
||||||
is_superuser: bool | None = None,
|
is_superuser: bool = False,
|
||||||
):
|
):
|
||||||
"""权限检查
|
"""权限检查
|
||||||
|
|
||||||
@@ -1325,8 +1258,6 @@ async def auth(
|
|||||||
ignore_flag = False
|
ignore_flag = False
|
||||||
if entity is None:
|
if entity is None:
|
||||||
entity = get_entity_ids(session)
|
entity = get_entity_ids(session)
|
||||||
if is_superuser is None:
|
|
||||||
is_superuser = session.user.id in bot.config.superusers
|
|
||||||
module = matcher.plugin_name or ""
|
module = matcher.plugin_name or ""
|
||||||
is_command_matcher = _is_command_matcher_class(type(matcher))
|
is_command_matcher = _is_command_matcher_class(type(matcher))
|
||||||
if event_cache is None:
|
if event_cache is None:
|
||||||
@@ -1451,8 +1382,12 @@ async def auth(
|
|||||||
else:
|
else:
|
||||||
ban_start = time.time()
|
ban_start = time.time()
|
||||||
try:
|
try:
|
||||||
await _call_auth_ban_compat(
|
await auth_ban(
|
||||||
matcher, bot, session, plugin, entity=entity
|
matcher,
|
||||||
|
session,
|
||||||
|
plugin,
|
||||||
|
entity=entity,
|
||||||
|
is_superuser=is_superuser,
|
||||||
)
|
)
|
||||||
hook_recorder.set("auth_ban", f"{time.time() - ban_start:.3f}s")
|
hook_recorder.set("auth_ban", f"{time.time() - ban_start:.3f}s")
|
||||||
if event_cache is not None:
|
if event_cache is not None:
|
||||||
@@ -1468,7 +1403,13 @@ async def auth(
|
|||||||
cost_start = time.time()
|
cost_start = time.time()
|
||||||
try:
|
try:
|
||||||
cost_gold = await with_timeout(
|
cost_gold = await with_timeout(
|
||||||
get_plugin_cost(bot, user, plugin, session), name="get_plugin_cost"
|
get_plugin_cost(
|
||||||
|
user,
|
||||||
|
plugin,
|
||||||
|
session,
|
||||||
|
is_superuser=is_superuser,
|
||||||
|
),
|
||||||
|
name="get_plugin_cost",
|
||||||
)
|
)
|
||||||
hook_recorder.set("cost_gold", f"{time.time() - cost_start:.3f}s")
|
hook_recorder.set("cost_gold", f"{time.time() - cost_start:.3f}s")
|
||||||
except asyncio.TimeoutError:
|
except asyncio.TimeoutError:
|
||||||
@@ -1622,6 +1563,20 @@ async def auth(
|
|||||||
|
|
||||||
except SkipPluginException as e:
|
except SkipPluginException as e:
|
||||||
LimitManager.unblock(module, entity.user_id, entity.group_id, entity.channel_id)
|
LimitManager.unblock(module, entity.user_id, entity.group_id, entity.channel_id)
|
||||||
|
if e.tip_message:
|
||||||
|
try:
|
||||||
|
tip_coro = send_message(
|
||||||
|
session,
|
||||||
|
e.tip_message,
|
||||||
|
e.tip_check_tag,
|
||||||
|
background=e.tip_background,
|
||||||
|
)
|
||||||
|
if e.tip_timeout and not e.tip_background:
|
||||||
|
await asyncio.wait_for(tip_coro, timeout=e.tip_timeout)
|
||||||
|
else:
|
||||||
|
await tip_coro
|
||||||
|
except asyncio.TimeoutError:
|
||||||
|
logger.error("发送权限提示超时", LOGGER_COMMAND, session=session)
|
||||||
logger.info(str(e), LOGGER_COMMAND, session=session)
|
logger.info(str(e), LOGGER_COMMAND, session=session)
|
||||||
ignore_flag = True
|
ignore_flag = True
|
||||||
auth_allowed = False
|
auth_allowed = False
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import asyncio
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -30,13 +29,6 @@ from .auth_checker import (
|
|||||||
|
|
||||||
_SKIP_AUTH_PLUGINS = {"chat_history", "chat_message"}
|
_SKIP_AUTH_PLUGINS = {"chat_history", "chat_message"}
|
||||||
_BOT_CONNECT_TS: float | None = None
|
_BOT_CONNECT_TS: float | None = None
|
||||||
_AUTH_QUEUE_MAXSIZE = 200
|
|
||||||
_AUTH_QUEUE: asyncio.Queue[tuple[Matcher, Event, Bot, Uninfo, UniMsg | None]] = (
|
|
||||||
asyncio.Queue(maxsize=_AUTH_QUEUE_MAXSIZE)
|
|
||||||
)
|
|
||||||
_AUTH_QUEUE_STARTED = False
|
|
||||||
_AUTH_WORKERS: list[asyncio.Task] = []
|
|
||||||
_LAST_DROP_LOG = 0.0
|
|
||||||
|
|
||||||
driver = get_driver()
|
driver = get_driver()
|
||||||
register_runtime_bootstrap(driver)
|
register_runtime_bootstrap(driver)
|
||||||
@@ -49,27 +41,6 @@ async def _mark_bot_connected(bot: Bot):
|
|||||||
_BOT_CONNECT_TS = time.time()
|
_BOT_CONNECT_TS = time.time()
|
||||||
|
|
||||||
|
|
||||||
async def _auth_worker(worker_id: int) -> None:
|
|
||||||
while True:
|
|
||||||
matcher, event, bot, session, message = await _AUTH_QUEUE.get()
|
|
||||||
try:
|
|
||||||
await auth(
|
|
||||||
matcher,
|
|
||||||
event,
|
|
||||||
bot,
|
|
||||||
session,
|
|
||||||
message,
|
|
||||||
skip_ban=True,
|
|
||||||
)
|
|
||||||
except IgnoredException:
|
|
||||||
pass
|
|
||||||
except Exception as exc:
|
|
||||||
if not is_overloaded():
|
|
||||||
logger.error("async auth failed", LOGGER_COMMAND, e=exc)
|
|
||||||
finally:
|
|
||||||
_AUTH_QUEUE.task_done()
|
|
||||||
|
|
||||||
|
|
||||||
def _extract_plain_text(message: UniMsg | None, event: Event) -> str:
|
def _extract_plain_text(message: UniMsg | None, event: Event) -> str:
|
||||||
if message is not None:
|
if message is not None:
|
||||||
with contextlib.suppress(Exception):
|
with contextlib.suppress(Exception):
|
||||||
@@ -82,33 +53,12 @@ def _extract_plain_text(message: UniMsg | None, event: Event) -> str:
|
|||||||
|
|
||||||
|
|
||||||
@driver.on_startup
|
@driver.on_startup
|
||||||
async def _start_auth_queue():
|
async def _start_auth_runtime_tasks():
|
||||||
global _AUTH_QUEUE_STARTED
|
|
||||||
if _AUTH_QUEUE_STARTED:
|
|
||||||
return
|
|
||||||
_AUTH_QUEUE_STARTED = True
|
|
||||||
worker_count = max(1, min(6, _AUTH_QUEUE_MAXSIZE // 50))
|
|
||||||
for idx in range(worker_count):
|
|
||||||
_AUTH_WORKERS.append(asyncio.create_task(_auth_worker(idx)))
|
|
||||||
await start_auth_runtime_tasks()
|
await start_auth_runtime_tasks()
|
||||||
|
|
||||||
|
|
||||||
@driver.on_shutdown
|
@driver.on_shutdown
|
||||||
async def _stop_auth_queue():
|
async def _stop_auth_runtime_tasks():
|
||||||
global _AUTH_QUEUE_STARTED
|
|
||||||
_AUTH_QUEUE_STARTED = False
|
|
||||||
workers = _AUTH_WORKERS.copy()
|
|
||||||
_AUTH_WORKERS.clear()
|
|
||||||
for task in workers:
|
|
||||||
task.cancel()
|
|
||||||
if workers:
|
|
||||||
await asyncio.gather(*workers, return_exceptions=True)
|
|
||||||
|
|
||||||
while not _AUTH_QUEUE.empty():
|
|
||||||
with contextlib.suppress(Exception):
|
|
||||||
_AUTH_QUEUE.get_nowait()
|
|
||||||
_AUTH_QUEUE.task_done()
|
|
||||||
|
|
||||||
await stop_auth_runtime_tasks()
|
await stop_auth_runtime_tasks()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ async def _():
|
|||||||
# if limit_create:
|
# if limit_create:
|
||||||
# await PluginLimit.bulk_create(limit_create, 10)
|
# await PluginLimit.bulk_create(limit_create, 10)
|
||||||
await PluginInfo.filter(module_path__in=load_plugin).update(load_status=True)
|
await PluginInfo.filter(module_path__in=load_plugin).update(load_status=True)
|
||||||
await PluginInfo.filter(module_path__not_in=load_plugin).delete()
|
await PluginInfo.filter(module_path__not_in=load_plugin).update(load_status=False)
|
||||||
from zhenxun.services.cache.runtime_cache import PluginInfoMemoryCache
|
from zhenxun.services.cache.runtime_cache import PluginInfoMemoryCache
|
||||||
|
|
||||||
await PluginInfoMemoryCache.refresh()
|
await PluginInfoMemoryCache.refresh()
|
||||||
|
|||||||
@@ -44,6 +44,30 @@ def row_style(column: str, text: str) -> RowStyle:
|
|||||||
|
|
||||||
|
|
||||||
class StoreManager:
|
class StoreManager:
|
||||||
|
@classmethod
|
||||||
|
def _resolve_local_plugin_path(
|
||||||
|
cls, plugin_info: StorePluginInfo, *, is_external: bool
|
||||||
|
) -> Path:
|
||||||
|
"""将商店插件信息映射到本地插件文件/目录路径。"""
|
||||||
|
plugin_name = plugin_info.module_path.split(".")[-1] or plugin_info.module
|
||||||
|
if is_external and plugin_info.is_dir and plugin_info.module_path == ".":
|
||||||
|
return BASE_PATH / "plugins" / plugin_name
|
||||||
|
|
||||||
|
relative_parts = [part for part in plugin_info.module_path.split(".") if part]
|
||||||
|
relative_path = Path(*relative_parts) if relative_parts else Path(plugin_name)
|
||||||
|
path = BASE_PATH.parent / relative_path
|
||||||
|
if plugin_info.is_dir:
|
||||||
|
return path
|
||||||
|
return path.parent / f"{plugin_name}.py"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _is_plugin_installed(
|
||||||
|
cls, plugin_info: StorePluginInfo, *, is_external: bool
|
||||||
|
) -> bool:
|
||||||
|
return cls._resolve_local_plugin_path(
|
||||||
|
plugin_info, is_external=is_external
|
||||||
|
).exists()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@cached(60)
|
@cached(60)
|
||||||
async def get_data(cls) -> tuple[list[StorePluginInfo], list[StorePluginInfo]]:
|
async def get_data(cls) -> tuple[list[StorePluginInfo], list[StorePluginInfo]]:
|
||||||
@@ -98,13 +122,16 @@ class StoreManager:
|
|||||||
return suc_plugin.get(module) and plugin_info.version == suc_plugin[module]
|
return suc_plugin.get(module) and plugin_info.version == suc_plugin[module]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_loaded_plugins(cls, *args) -> list[tuple[str, str]]:
|
async def get_installed_plugins(cls) -> dict[str, str]:
|
||||||
"""获取已加载的插件
|
"""获取已安装插件的模块与版本。
|
||||||
|
|
||||||
返回:
|
返回:
|
||||||
list[str]: 已加载的插件
|
dict[str, str]: 模块 -> 版本
|
||||||
"""
|
"""
|
||||||
return await PluginInfo.get_plugins_values_list(*args, load_status=True)
|
db_plugin_list = await PluginInfo.get_plugins_values_list(
|
||||||
|
"module", "version", load_status=True, filter_parent=False
|
||||||
|
)
|
||||||
|
return {p[0]: (p[1] or "0.1") for p in db_plugin_list}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get_plugins_info(cls) -> list[BuildImage] | str:
|
async def get_plugins_info(cls) -> list[BuildImage] | str:
|
||||||
@@ -115,8 +142,7 @@ class StoreManager:
|
|||||||
"""
|
"""
|
||||||
plugin_list, extra_plugin_list = await cls.get_data()
|
plugin_list, extra_plugin_list = await cls.get_data()
|
||||||
column_name = ["-", "ID", "名称", "简介", "作者", "版本", "类型"]
|
column_name = ["-", "ID", "名称", "简介", "作者", "版本", "类型"]
|
||||||
db_plugin_list = await cls.get_loaded_plugins("module", "version")
|
suc_plugin = await cls.get_installed_plugins()
|
||||||
suc_plugin = {p[0]: (p[1] or "0.1") for p in db_plugin_list}
|
|
||||||
index = 0
|
index = 0
|
||||||
data_list = []
|
data_list = []
|
||||||
extra_data_list = []
|
extra_data_list = []
|
||||||
@@ -190,7 +216,6 @@ class StoreManager:
|
|||||||
plugin_list, extra_plugin_list = await cls.get_data()
|
plugin_list, extra_plugin_list = await cls.get_data()
|
||||||
plugin_info = None
|
plugin_info = None
|
||||||
is_external = False
|
is_external = False
|
||||||
db_plugin_list = await cls.get_loaded_plugins("module")
|
|
||||||
try:
|
try:
|
||||||
plugin_key = await cls._resolve_plugin_key(index_or_module)
|
plugin_key = await cls._resolve_plugin_key(index_or_module)
|
||||||
except PluginStoreException:
|
except PluginStoreException:
|
||||||
@@ -211,7 +236,7 @@ class StoreManager:
|
|||||||
plugin_info = p
|
plugin_info = p
|
||||||
break
|
break
|
||||||
|
|
||||||
modules = [p[0] for p in db_plugin_list]
|
installed_modules = set((await cls.get_installed_plugins()).keys())
|
||||||
|
|
||||||
if is_remove:
|
if is_remove:
|
||||||
# 商店列表中找不到时,从数据库构建最小插件信息
|
# 商店列表中找不到时,从数据库构建最小插件信息
|
||||||
@@ -237,13 +262,17 @@ class StoreManager:
|
|||||||
is_dir=_path.is_dir(),
|
is_dir=_path.is_dir(),
|
||||||
)
|
)
|
||||||
is_external = True
|
is_external = True
|
||||||
if plugin_info.module not in modules:
|
if plugin_info.module not in installed_modules:
|
||||||
raise PluginStoreException(f"插件 {plugin_info.name} 未安装,无法移除")
|
raise PluginStoreException(f"插件 {plugin_info.name} 未安装,无法移除")
|
||||||
if plugin_obj := await PluginInfo.get_plugin(
|
if plugin_obj := await PluginInfo.get_plugin(
|
||||||
module=plugin_info.module, plugin_type=PluginType.PARENT
|
module=plugin_info.module,
|
||||||
|
plugin_type=PluginType.PARENT,
|
||||||
|
load_status=True,
|
||||||
):
|
):
|
||||||
plugin_info.module_path = plugin_obj.module_path
|
plugin_info.module_path = plugin_obj.module_path
|
||||||
elif plugin_obj := await PluginInfo.get_plugin(module=plugin_info.module):
|
elif plugin_obj := await PluginInfo.get_plugin(
|
||||||
|
module=plugin_info.module, load_status=True
|
||||||
|
):
|
||||||
plugin_info.module_path = plugin_obj.module_path
|
plugin_info.module_path = plugin_obj.module_path
|
||||||
return plugin_info, is_external
|
return plugin_info, is_external
|
||||||
|
|
||||||
@@ -251,11 +280,11 @@ class StoreManager:
|
|||||||
raise PluginStoreException(f"插件不存在: {plugin_key}")
|
raise PluginStoreException(f"插件不存在: {plugin_key}")
|
||||||
|
|
||||||
if is_update:
|
if is_update:
|
||||||
if plugin_info.module not in modules:
|
if plugin_info.module not in installed_modules:
|
||||||
raise PluginStoreException(f"插件 {plugin_info.name} 未安装,无法更新")
|
raise PluginStoreException(f"插件 {plugin_info.name} 未安装,无法更新")
|
||||||
return plugin_info, is_external
|
return plugin_info, is_external
|
||||||
|
|
||||||
if plugin_info.module in modules:
|
if plugin_info.module in installed_modules:
|
||||||
raise PluginStoreException(f"插件 {plugin_info.name} 已安装,无需重复安装")
|
raise PluginStoreException(f"插件 {plugin_info.name} 已安装,无需重复安装")
|
||||||
|
|
||||||
return plugin_info, is_external
|
return plugin_info, is_external
|
||||||
@@ -391,11 +420,8 @@ class StoreManager:
|
|||||||
str: 返回消息
|
str: 返回消息
|
||||||
"""
|
"""
|
||||||
plugin_info, _ = await cls.get_plugin_by_value(index_or_module, is_remove=True)
|
plugin_info, _ = await cls.get_plugin_by_value(index_or_module, is_remove=True)
|
||||||
module_path = plugin_info.module_path
|
is_external = not plugin_info.module_path.startswith("zhenxun.")
|
||||||
module = module_path.split(".")[-1]
|
path = cls._resolve_local_plugin_path(plugin_info, is_external=is_external)
|
||||||
path = BASE_PATH.parent / Path(module_path.replace(".", os.sep))
|
|
||||||
if not plugin_info.is_dir:
|
|
||||||
path = path.parent / f"{module}.py"
|
|
||||||
if not path.exists():
|
if not path.exists():
|
||||||
return f"插件 {plugin_info.name} 不存在..."
|
return f"插件 {plugin_info.name} 不存在..."
|
||||||
logger.debug(f"尝试移除插件 {plugin_info.name} 文件: {path}", LOG_COMMAND)
|
logger.debug(f"尝试移除插件 {plugin_info.name} 文件: {path}", LOG_COMMAND)
|
||||||
@@ -404,7 +430,14 @@ class StoreManager:
|
|||||||
shutil.rmtree(path, onerror=win_on_rm_error)
|
shutil.rmtree(path, onerror=win_on_rm_error)
|
||||||
else:
|
else:
|
||||||
path.unlink()
|
path.unlink()
|
||||||
await PluginInitManager.remove(module_path)
|
await PluginInitManager.remove(plugin_info.module_path)
|
||||||
|
plugin_records = await PluginInfo.get_plugins(
|
||||||
|
load_status=None,
|
||||||
|
filter_parent=False,
|
||||||
|
module_path=plugin_info.module_path,
|
||||||
|
)
|
||||||
|
for plugin_record in plugin_records:
|
||||||
|
await plugin_record.delete()
|
||||||
return f"插件 {plugin_info.name} 移除成功! 重启后生效"
|
return f"插件 {plugin_info.name} 移除成功! 重启后生效"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -419,8 +452,7 @@ class StoreManager:
|
|||||||
"""
|
"""
|
||||||
plugin_list, extra_plugin_list = await cls.get_data()
|
plugin_list, extra_plugin_list = await cls.get_data()
|
||||||
all_plugin_list = plugin_list + extra_plugin_list
|
all_plugin_list = plugin_list + extra_plugin_list
|
||||||
db_plugin_list = await cls.get_loaded_plugins("module", "version")
|
suc_plugin = await cls.get_installed_plugins()
|
||||||
suc_plugin = {p[0]: (p[1] or "Unknown") for p in db_plugin_list}
|
|
||||||
filtered_data = [
|
filtered_data = [
|
||||||
(id, plugin_info)
|
(id, plugin_info)
|
||||||
for id, plugin_info in enumerate(all_plugin_list)
|
for id, plugin_info in enumerate(all_plugin_list)
|
||||||
@@ -463,8 +495,7 @@ class StoreManager:
|
|||||||
"""
|
"""
|
||||||
plugin_info, is_external = await cls.get_plugin_by_value(index_or_module, True)
|
plugin_info, is_external = await cls.get_plugin_by_value(index_or_module, True)
|
||||||
logger.info(f"尝试更新插件 {plugin_info.name}", LOG_COMMAND)
|
logger.info(f"尝试更新插件 {plugin_info.name}", LOG_COMMAND)
|
||||||
db_plugin_list = await cls.get_loaded_plugins("module", "version")
|
suc_plugin = await cls.get_installed_plugins()
|
||||||
suc_plugin = {p[0]: (p[1] or "Unknown") for p in db_plugin_list}
|
|
||||||
logger.debug(f"当前插件列表: {suc_plugin}", LOG_COMMAND)
|
logger.debug(f"当前插件列表: {suc_plugin}", LOG_COMMAND)
|
||||||
if cls.check_version_is_new(plugin_info, suc_plugin):
|
if cls.check_version_is_new(plugin_info, suc_plugin):
|
||||||
return f"插件 {plugin_info.name} 已是最新版本"
|
return f"插件 {plugin_info.name} 已是最新版本"
|
||||||
@@ -493,11 +524,10 @@ class StoreManager:
|
|||||||
update_success_list = []
|
update_success_list = []
|
||||||
result = "--已更新{}个插件 {}个失败 {}个成功--"
|
result = "--已更新{}个插件 {}个失败 {}个成功--"
|
||||||
logger.info(f"尝试更新全部插件 {plugin_name_list}", LOG_COMMAND)
|
logger.info(f"尝试更新全部插件 {plugin_name_list}", LOG_COMMAND)
|
||||||
|
suc_plugin = await cls.get_installed_plugins()
|
||||||
for plugin_info in all_plugin_list:
|
for plugin_info in all_plugin_list:
|
||||||
try:
|
try:
|
||||||
db_plugin_list = await cls.get_loaded_plugins("module", "version")
|
if plugin_info.module not in suc_plugin:
|
||||||
suc_plugin = {p[0]: (p[1] or "Unknown") for p in db_plugin_list}
|
|
||||||
if plugin_info.module not in [p[0] for p in db_plugin_list]:
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"插件 {plugin_info.name}({plugin_info.module}) 未安装,跳过",
|
f"插件 {plugin_info.name}({plugin_info.module}) 未安装,跳过",
|
||||||
LOG_COMMAND,
|
LOG_COMMAND,
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from fastapi.responses import JSONResponse
|
|||||||
from nonebot import require
|
from nonebot import require
|
||||||
from nonebot.compat import model_dump
|
from nonebot.compat import model_dump
|
||||||
|
|
||||||
from zhenxun.models.plugin_info import PluginInfo
|
|
||||||
from zhenxun.services.log import logger
|
from zhenxun.services.log import logger
|
||||||
|
|
||||||
from ....base_model import Result
|
from ....base_model import Result
|
||||||
@@ -30,7 +29,7 @@ async def _() -> Result[dict]:
|
|||||||
{**model_dump(plugin), "name": plugin.name, "id": idx}
|
{**model_dump(plugin), "name": plugin.name, "id": idx}
|
||||||
for idx, plugin in enumerate(plugin_list + extra_plugin_list)
|
for idx, plugin in enumerate(plugin_list + extra_plugin_list)
|
||||||
]
|
]
|
||||||
modules = await PluginInfo.get_plugins_values_list("module", load_status=True)
|
modules = list((await StoreManager.get_installed_plugins()).keys())
|
||||||
return Result.ok({"install_module": modules, "plugin_list": plugin_list})
|
return Result.ok({"install_module": modules, "plugin_list": plugin_list})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("获取插件商店插件信息失败", "WebUi", e=e)
|
logger.error("获取插件商店插件信息失败", "WebUi", e=e)
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
from nonebot.adapters import Bot, Event
|
from nonebot.adapters import Bot, Event
|
||||||
|
from nonebot.adapters.onebot.v11 import Bot as OneBotV11Bot
|
||||||
|
from nonebot.adapters.onebot.v12 import Bot as OneBotV12Bot
|
||||||
from nonebot.plugin import PluginMetadata
|
from nonebot.plugin import PluginMetadata
|
||||||
from nonebot.rule import Rule
|
from nonebot.rule import Rule
|
||||||
from nonebot_plugin_alconna import Alconna, Arparma, on_alconna
|
from nonebot_plugin_alconna import Alconna, Arparma, on_alconna
|
||||||
@@ -48,18 +50,27 @@ def reply_check() -> Rule:
|
|||||||
_matcher = on_alconna(Alconna("撤回"), priority=5, block=True, rule=reply_check())
|
_matcher = on_alconna(Alconna("撤回"), priority=5, block=True, rule=reply_check())
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_delete_message_id(bot: Bot, reply_id: str | int):
|
||||||
|
if isinstance(bot, OneBotV11Bot):
|
||||||
|
return int(reply_id)
|
||||||
|
if isinstance(bot, OneBotV12Bot):
|
||||||
|
return str(reply_id)
|
||||||
|
return reply_id
|
||||||
|
|
||||||
|
|
||||||
@_matcher.handle()
|
@_matcher.handle()
|
||||||
async def _(bot: Bot, event: Event, session: Uninfo, arparma: Arparma):
|
async def _(bot: Bot, event: Event, session: Uninfo, arparma: Arparma):
|
||||||
if reply := await reply_fetch(event, bot):
|
if reply := await reply_fetch(event, bot):
|
||||||
|
message_id = _resolve_delete_message_id(bot, reply.id)
|
||||||
if session.user.id in bot.config.superusers:
|
if session.user.id in bot.config.superusers:
|
||||||
try:
|
try:
|
||||||
await bot.delete_msg(message_id=reply.id)
|
await bot.delete_msg(message_id=message_id)
|
||||||
logger.info("撤回消息", arparma.header_result, session=session)
|
logger.info("撤回消息", arparma.header_result, session=session)
|
||||||
except Exception:
|
except Exception:
|
||||||
await MessageUtils.build_message("撤回失败,可能消息已过期...").send()
|
await MessageUtils.build_message("撤回失败,可能消息已过期...").send()
|
||||||
elif MessageManager.check(session.user.id, reply.id):
|
elif MessageManager.check(session.user.id, reply.id):
|
||||||
try:
|
try:
|
||||||
await bot.delete_msg(message_id=reply.id)
|
await bot.delete_msg(message_id=message_id)
|
||||||
logger.info("撤回消息", arparma.header_result, session=session)
|
logger.info("撤回消息", arparma.header_result, session=session)
|
||||||
except Exception:
|
except Exception:
|
||||||
await MessageUtils.build_message("撤回失败,可能消息已过期...").send()
|
await MessageUtils.build_message("撤回失败,可能消息已过期...").send()
|
||||||
|
|||||||
Reference in New Issue
Block a user