Skip to content

Commit

Permalink
🐛 修复添加插件依赖更新 (#1837)
Browse files Browse the repository at this point in the history
* 🐛 修复添加插件依赖更新

* 🔧 修改插件依赖安装命令为使用poetry运行pip

* 🐛 修复群组入群与退群提示

* 🐛 修复群组踢出用户提醒

* 🎨 代码优化

* 🎨 群欢迎迁移优化

* 🩹 精确webui调用统计

* 🚨 auto fix by pre-commit hooks

* 🐛 修复测试

* 🎨 fix pre-commit.ci

* 🎨  fix pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
HibiKier and pre-commit-ci[bot] authored Feb 3, 2025
1 parent d6fd5f1 commit 4ed1791
Show file tree
Hide file tree
Showing 15 changed files with 247 additions and 108 deletions.
28 changes: 24 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ python-jose = { extras = ["cryptography"], version = "^3.3.0" }
python-multipart = "^0.0.9"
aiocache = "^0.12.2"
py-cpuinfo = "^9.0.0"
nonebot-plugin-uninfo = "^0.4.1"
nonebot-plugin-alconna = "^0.54.0"
tenacity = "^9.0.0"
nonebot-plugin-uninfo = ">0.4.1"

[tool.poetry.group.dev.dependencies]
nonebug = "^0.4"
Expand Down
33 changes: 32 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from pytest_mock import MockerFixture
from respx import MockRouter

from tests.config import BotId, UserId
from tests.config import BotId, GroupId, UserId

nonebot.load_plugin("nonebot_plugin_session")

Expand Down Expand Up @@ -64,6 +64,37 @@ def _init_bot(nonebug_init: None):
nonebot.load_plugins("zhenxun/builtin_plugins")
nonebot.load_plugins("zhenxun/plugins")

# 手动缓存 uninfo 所需信息
from nonebot_plugin_uninfo import (
Scene,
SceneType,
Session,
SupportAdapter,
SupportScope,
User,
)
from nonebot_plugin_uninfo.adapters.onebot11.main import fetcher as onebot11_fetcher
from nonebot_plugin_uninfo.adapters.onebot12.main import fetcher as onebot12_fetcher

onebot11_fetcher.session_cache = {
f"group_{GroupId.GROUP_ID_LEVEL_5}_{UserId.SUPERUSER}": Session(
self_id="test",
adapter=SupportAdapter.onebot11,
scope=SupportScope.qq_client,
scene=Scene(str(GroupId.GROUP_ID_LEVEL_0), SceneType.GROUP),
user=User(str(UserId.SUPERUSER)),
),
}
onebot12_fetcher.session_cache = {
f"group_{GroupId.GROUP_ID_LEVEL_5}_{UserId.SUPERUSER}": Session(
self_id="test",
adapter=SupportAdapter.onebot12,
scope=SupportScope.qq_client,
scene=Scene(str(GroupId.GROUP_ID_LEVEL_0), SceneType.GROUP),
user=User(str(UserId.SUPERUSER)),
),
}


@pytest.fixture
async def app(app: App, tmp_path: Path, mocker: MockerFixture):
Expand Down
2 changes: 2 additions & 0 deletions zhenxun/builtin_plugins/admin/welcome_message/data_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ def migrate(path: Path):
path: 路径
"""
text_file = path / "text.json"
if not text_file.exists():
return
with text_file.open(encoding="utf8") as f:
json_data = json.load(f)
new_data = {}
Expand Down
14 changes: 7 additions & 7 deletions zhenxun/builtin_plugins/platform/qq/group_handle/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
group_decrease_handle = on_notice(
priority=1,
block=False,
rule=notice_rule([GroupMemberDecreaseEvent, GroupMemberIncreaseEvent]),
rule=notice_rule([GroupMemberDecreaseEvent, GroupDecreaseNoticeEvent]),
)
"""群员减少处理"""
add_group = on_request(priority=1, block=False)
Expand All @@ -116,19 +116,19 @@ async def _(
session: Uninfo,
event: GroupIncreaseNoticeEvent | GroupMemberIncreaseEvent,
):
user_id = str(event.user_id)
group_id = str(event.group_id)
if user_id == bot.self_id:
if session.user.id == bot.self_id:
"""新成员为bot本身"""
group, _ = await GroupConsole.get_or_create(
group_id=group_id, channel_id__isnull=True
group_id=str(event.group_id), channel_id__isnull=True
)
try:
await GroupManager.add_bot(bot, str(event.operator_id), group_id, group)
await GroupManager.add_bot(
bot, str(event.operator_id), str(event.group_id), group
)
except ForceAddGroupError as e:
await PlatformUtils.send_superuser(bot, e.get_info())
else:
await GroupManager.add_user(session, bot, user_id, group_id)
await GroupManager.add_user(session, bot)


@group_decrease_handle.handle()
Expand Down
58 changes: 37 additions & 21 deletions zhenxun/builtin_plugins/platform/qq/group_handle/data_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import random

from nonebot.adapters import Bot
from nonebot.exception import ActionFailed
from nonebot_plugin_alconna import At, UniMessage
from nonebot_plugin_uninfo import Uninfo
import ujson as json
Expand Down Expand Up @@ -54,7 +55,7 @@ async def __handle_add_group(
if plugin_list := await PluginInfo.filter(default_status=False).all():
for plugin in plugin_list:
block_plugin += f"<{plugin.module},"
group_info = await bot.get_group_info(group_id=group_id)
group_info = await bot.get_group_info(group_id=group_id, no_cache=True)
await GroupConsole.create(
group_id=group_info["group_id"],
group_name=group_info["group_name"],
Expand Down Expand Up @@ -215,33 +216,45 @@ async def __send_welcome_message(cls, session: Uninfo, user_id: str):
msg_list.insert(0, At("user", user_id))
logger.info("发送群欢迎消息...", "入群检测", session=session)
if msg_list:
await MessageUtils.build_message(msg_list).send() # type: ignore
else:
image = DEFAULT_IMAGE_PATH / random.choice(
os.listdir(DEFAULT_IMAGE_PATH)
)
await MessageUtils.build_message(
[
"新人快跑啊!!本群现状↓(快使用自定义群欢迎消息!)",
image,
]
).send()
await MessageUtils.build_message(msg_list).finish() # type: ignore
image = DEFAULT_IMAGE_PATH / random.choice(os.listdir(DEFAULT_IMAGE_PATH))
await MessageUtils.build_message(
[
"新人快跑啊!!本群现状↓(快使用自定义群欢迎消息!)",
image,
]
).send()

@classmethod
async def add_user(cls, session: Uninfo, bot: Bot, user_id: str, group_id: str):
async def add_user(cls, session: Uninfo, bot: Bot):
"""拉入用户
参数:
session: Uninfo
bot: Bot
user_id: 用户id
group_id: 群组id
"""
user_id = session.user.id
group_id = ""
if session.group:
if session.group.parent:
group_id = session.group.parent.id
else:
group_id = session.group.id
join_time = datetime.now()
user_info = await bot.get_group_member_info(group_id=group_id, user_id=user_id)
try:
user_info = await bot.get_group_member_info(
group_id=int(group_id), user_id=int(user_id), no_cache=True
)
except ActionFailed as e:
logger.warning("获取用户信息识别...", e=e)
user_info = {"user_id": user_id, "group_id": group_id, "nickname": ""}
await GroupInfoUser.update_or_create(
user_id=str(user_info["user_id"]),
group_id=str(user_info["group_id"]),
defaults={"user_name": user_info["nickname"], "user_join_time": join_time},
defaults={
"user_name": user_info["nickname"],
"user_join_time": join_time,
},
)
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
if not await CommonUtils.task_is_block(
Expand Down Expand Up @@ -310,10 +323,13 @@ async def run_user(
group_id=group_id,
)
if sub_type == "kick":
operator = await bot.get_group_member_info(
user_id=int(operator_id), group_id=int(group_id)
)
operator_name = operator["card"] or operator["nickname"]
if operator_id != "0":
operator = await bot.get_group_member_info(
user_id=int(operator_id), group_id=int(group_id)
)
operator_name = operator["card"] or operator["nickname"]
else:
operator_name = ""
return f"{user_name}{operator_name} 送走了."
elif sub_type == "leave":
return f"{user_name}离开了我们..."
Expand Down
4 changes: 2 additions & 2 deletions zhenxun/builtin_plugins/plugin_store/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@
)

_matcher.shortcut(
r"添加插件",
r"(添加|安装)插件",
command="插件商店",
arguments=["add", "{%0}"],
prefix=True,
)

_matcher.shortcut(
r"移除插件",
r"(移除|卸载)插件",
command="插件商店",
arguments=["remove", "{%0}"],
prefix=True,
Expand Down
46 changes: 27 additions & 19 deletions zhenxun/builtin_plugins/plugin_store/data_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def install_requirement(plugin_path: Path):

try:
result = subprocess.run(
["pip", "install", "-r", str(existing_requirements)],
["poetry", "run", "pip", "install", "-r", str(existing_requirements)],
check=True,
capture_output=True,
text=True,
Expand Down Expand Up @@ -232,8 +232,9 @@ async def install_plugin_with_repo(
raise ValueError("所有API获取插件文件失败,请检查网络连接")
if module_path == ".":
module_path = ""
replace_module_path = module_path.replace(".", "/")
files = repo_api.get_files(
module_path=module_path.replace(".", "/") + ("" if is_dir else ".py"),
module_path=replace_module_path + ("" if is_dir else ".py"),
is_dir=is_dir,
)
download_urls = [await repo_info.get_raw_download_urls(file) for file in files]
Expand All @@ -248,25 +249,32 @@ async def install_plugin_with_repo(
else:
# 安装依赖
plugin_path = base_path / "/".join(module_path.split("."))
req_files = repo_api.get_files(REQ_TXT_FILE_STRING, False)
req_files.extend(repo_api.get_files("requirement.txt", False))
logger.debug(f"获取插件依赖文件列表: {req_files}", "插件管理")
req_download_urls = [
await repo_info.get_raw_download_urls(file) for file in req_files
]
req_paths: list[Path | str] = [plugin_path / file for file in req_files]
logger.debug(f"插件依赖文件下载路径: {req_paths}", "插件管理")
if req_files:
result = await AsyncHttpx.gather_download_file(
req_download_urls, req_paths
try:
req_files = repo_api.get_files(
f"{replace_module_path}/{REQ_TXT_FILE_STRING}", False
)
req_files.extend(
repo_api.get_files(f"{replace_module_path}/requirement.txt", False)
)
for success in result:
if not success:
raise Exception("插件依赖文件下载失败")
logger.debug(f"插件依赖文件列表: {req_paths}", "插件管理")
install_requirement(plugin_path)
logger.debug(f"获取插件依赖文件列表: {req_files}", "插件管理")
req_download_urls = [
await repo_info.get_raw_download_urls(file) for file in req_files
]
req_paths: list[Path | str] = [plugin_path / file for file in req_files]
logger.debug(f"插件依赖文件下载路径: {req_paths}", "插件管理")
if req_files:
result = await AsyncHttpx.gather_download_file(
req_download_urls, req_paths
)
for success in result:
if not success:
raise Exception("插件依赖文件下载失败")
logger.debug(f"插件依赖文件列表: {req_paths}", "插件管理")
install_requirement(plugin_path)
except ValueError as e:
logger.warning("未获取到依赖文件路径...", e=e)
return True
raise Exception("插件下载失败")
raise Exception("插件下载失败...")

@classmethod
async def remove_plugin(cls, plugin_id: str) -> str:
Expand Down
5 changes: 4 additions & 1 deletion zhenxun/builtin_plugins/sign_in/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from zhenxun.models.sign_user import SignUser
from zhenxun.utils.http_utils import AsyncHttpx
from zhenxun.utils.image_utils import BuildImage
from zhenxun.utils.platform import PlatformUtils

from .config import (
SIGN_BACKGROUND_PATH,
Expand Down Expand Up @@ -430,7 +431,9 @@ async def _generate_html_card(
)
now = datetime.now()
data = {
"ava_url": session.user.avatar,
"ava_url": PlatformUtils.get_user_avatar_url(
user.user_id, PlatformUtils.get_platform(session), session.self_id
),
"name": nickname,
"uid": uid,
"sign_count": f"{user.sign_count}",
Expand Down
26 changes: 22 additions & 4 deletions zhenxun/builtin_plugins/web_ui/api/tabs/main/data_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,13 +248,31 @@ def __get_query(
if bot_id:
query = query.filter(bot_id=bot_id)
if date_type == QueryDateType.DAY:
query = query.filter(create_time__gte=now - timedelta(hours=now.hour))
query = query.filter(
create_time__gte=now
- timedelta(hours=now.hour, minutes=now.minute, seconds=now.second)
)
if date_type == QueryDateType.WEEK:
query = query.filter(create_time__gte=now - timedelta(days=7))
query = query.filter(
create_time__gte=now
- timedelta(
days=7, hours=now.hour, minutes=now.minute, seconds=now.second
)
)
if date_type == QueryDateType.MONTH:
query = query.filter(create_time__gte=now - timedelta(days=30))
query = query.filter(
create_time__gte=now
- timedelta(
days=30, hours=now.hour, minutes=now.minute, seconds=now.second
)
)
if date_type == QueryDateType.YEAR:
query = query.filter(create_time__gte=now - timedelta(days=365))
query = query.filter(
create_time__gte=now
- timedelta(
days=365, hours=now.hour, minutes=now.minute, seconds=now.second
)
)
return query

@classmethod
Expand Down
2 changes: 2 additions & 0 deletions zhenxun/configs/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

from .utils import ConfigsManager

__all__ = ["BotConfig", "Config"]


class BotSetting(BaseModel):
self_nickname: str = ""
Expand Down
Loading

0 comments on commit 4ed1791

Please sign in to comment.