From 9e5266a4910a667b9fbd6a30b9b1eff2f06fb020 Mon Sep 17 00:00:00 2001 From: HibiKier <45528451+HibiKier@users.noreply.github.com> Date: Thu, 10 Oct 2024 23:25:46 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20=E4=BD=BF=E7=94=A8uninfo=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E7=BE=A4=E7=BB=84=E6=88=90=E5=91=98=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=20(#1690)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- poetry.lock | 22 +- pyproject.toml | 1 + .../admin/group_member_update/__init__.py | 13 +- .../admin/group_member_update/_data_source.py | 304 +++++++----------- zhenxun/utils/platform.py | 14 +- 5 files changed, 144 insertions(+), 210 deletions(-) diff --git a/poetry.lock b/poetry.lock index e3a0dab3..fd2e82ca 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2511,6 +2511,26 @@ type = "legacy" url = "https://mirrors.aliyun.com/pypi/simple" reference = "ali" +[[package]] +name = "nonebot-plugin-uninfo" +version = "0.4.0" +description = "Universal Information Model for Nonebot2" +optional = false +python-versions = ">=3.9" +files = [ + {file = "nonebot_plugin_uninfo-0.4.0-py3-none-any.whl", hash = "sha256:d60a8491af52b1b2c0cdb3f2e4a4a8d02e66216a33e8d162f1da8bec73b3b701"}, + {file = "nonebot_plugin_uninfo-0.4.0.tar.gz", hash = "sha256:3e1a494d05639a0227a8565d5cde90ec9724934a7ec32bf1e0bd40404faf9713"}, +] + +[package.dependencies] +importlib-metadata = ">=4.13.0" +nonebot2 = ">=2.3.0" + +[package.source] +type = "legacy" +url = "https://mirrors.aliyun.com/pypi/simple" +reference = "ali" + [[package]] name = "nonebot-plugin-userinfo" version = "0.1.3" @@ -4925,4 +4945,4 @@ reference = "ali" [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "e66133515a2b17715ddf5f887ec31f128751acda1ea67736e9d27b29a9b16b65" +content-hash = "527819a6117da3c41931d968f9238468aee98f2ca97f06e1ba1e7948b6cbe65c" diff --git a/pyproject.toml b/pyproject.toml index d582538b..0bb4acc5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,6 +51,7 @@ nonebot-plugin-alconna = "0.51.1" arclet-alconna = "1.8.23" aiocache = "^0.12.2" py-cpuinfo = "^9.0.0" +nonebot-plugin-uninfo = "^0.4.1" [tool.poetry.dev-dependencies] nonebug = "^0.3.2" diff --git a/zhenxun/builtin_plugins/admin/group_member_update/__init__.py b/zhenxun/builtin_plugins/admin/group_member_update/__init__.py index 72532b09..4c63790d 100644 --- a/zhenxun/builtin_plugins/admin/group_member_update/__init__.py +++ b/zhenxun/builtin_plugins/admin/group_member_update/__init__.py @@ -49,18 +49,15 @@ _notice = on_notice(priority=1, block=False, rule=notice_rule(GroupIncreaseNotic async def _(bot: Bot, session: EventSession, arparma: Arparma): if gid := session.id3 or session.id2: logger.info("更新群组成员信息", arparma.header_result, session=session) - await MemberUpdateManage.update(bot, gid) - await MessageUtils.build_message("已经成功更新了群组成员信息!").finish( - reply_to=True - ) + result = await MemberUpdateManage.update_group_member(bot, gid) + await MessageUtils.build_message(result).finish(reply_to=True) await MessageUtils.build_message("群组id为空...").send() @_notice.handle() async def _(bot: Bot, event: GroupIncreaseNoticeEvent): - # TODO: 其他适配器的加群自动更新群组成员信息 if str(event.user_id) == bot.self_id: - await MemberUpdateManage.update(bot, str(event.group_id)) + await MemberUpdateManage.update_group_member(bot, str(event.group_id)) logger.info( f"{BotConfig.self_nickname}加入群聊更新群组信息", "更新群组成员列表", @@ -81,7 +78,9 @@ async def _(): if group_list: for group in group_list: try: - await MemberUpdateManage.update(bot, group.group_id) + await MemberUpdateManage.update_group_member( + bot, group.group_id + ) logger.debug("自动更新群组成员信息成功...") except Exception as e: logger.error( diff --git a/zhenxun/builtin_plugins/admin/group_member_update/_data_source.py b/zhenxun/builtin_plugins/admin/group_member_update/_data_source.py index 6ece97cc..cf478018 100644 --- a/zhenxun/builtin_plugins/admin/group_member_update/_data_source.py +++ b/zhenxun/builtin_plugins/admin/group_member_update/_data_source.py @@ -1,213 +1,129 @@ -from datetime import datetime, timezone, timedelta - +import nonebot from nonebot.adapters import Bot - -# from nonebot.adapters.kaiheila import Bot as KaiheilaBot -from nonebot.adapters.onebot.v11 import Bot as v11Bot -from nonebot.adapters.onebot.v12 import Bot as v12Bot +from nonebot_plugin_uninfo import Member, SceneType, get_interface from zhenxun.services.log import logger from zhenxun.configs.config import Config from zhenxun.models.level_user import LevelUser +from zhenxun.utils.platform import PlatformUtils from zhenxun.models.group_member_info import GroupInfoUser -# from nonebot.adapters.discord import Bot as DiscordBot -# from nonebot.adapters.dodo import Bot as DodoBot - class MemberUpdateManage: - @classmethod - async def update(cls, bot: Bot, group_id: str): - if not group_id: - return logger.warning( - f"bot: {bot.self_id},group_id为空,无法更新群成员信息..." - ) - if isinstance(bot, v11Bot): - await cls.v11(bot, group_id) - elif isinstance(bot, v12Bot): - await cls.v12(bot, group_id) - # elif isinstance(bot, KaiheilaBot): - # await cls.kaiheila(bot, group_id) - # elif isinstance(bot, DodoBot): - # await cls.dodo(bot, group_id) - # elif isinstance(bot, DiscordBot): - # await cls.discord(bot, group_id) + async def __handle_user( + cls, + member: Member, + db_user: list[GroupInfoUser], + group_id: str, + data_list: tuple[list, list, list], + platform: str | None, + ): + """单个成员操作 - # @classmethod - # async def discord(cls, bot: DiscordBot, group_id: str): - # # TODO: discord更新群组成员信息 - # pass - - # @classmethod - # async def dodo(cls, bot: DodoBot, group_id: str): - # page_size = 100 - # result_size = 100 - # max_id = 0 - # exist_member_list = [] - # group_member_list: list[MemberInfo] = [] - # while result_size == page_size: - # group_member_data = await bot.get_member_list( - # island_source_id=group_id, page_size=page_size - # ) - # result_size = len(group_member_data.list) - # group_member_list += group_member_data.list - # max_id = group_member_data.max_id - # if group_member_list: - # for user in group_member_list: - # exist_member_list.append(user.dodo_source_id) - # await GroupInfoUser.update_or_create( - # user_id=user.dodo_source_id, - # group_id=group_id, - # defaults={ - # "user_name": user.nick_name or user.personal_nick_name, - # "user_join_time": user.join_time, - # "platform": "dodo", - # }, - # ) - # if delete_member_list := list( - # set(exist_member_list).difference( - # set(await GroupInfoUser.get_group_member_id_list(group_id)) - # ) - # ): - # await GroupInfoUser.filter( - # user_id__in=delete_member_list, group_id=group_id - # ).delete() - # logger.info( - # f"删除已退群用户", - # "更新群组成员信息", - # group_id=group_id, - # platform="dodo", - # ) - - # @classmethod - # async def kaiheila(cls, bot: KaiheilaBot, group_id: str): - # # TODO: kaiheila 更新群组成员信息 - # pass - - @classmethod - async def v11(cls, bot: v11Bot, group_id: str): - exist_member_list = [] + 参数: + member: Member + db_user: db成员数据 + group_id: 群组id + data_list: 数据列表 + platform: 平台 + """ + driver = nonebot.get_driver() default_auth = Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH") - group_member_list = await bot.get_group_member_list(group_id=int(group_id)) - db_user = await GroupInfoUser.filter(group_id=group_id).all() + nickname = member.nick or member.user.name or "" + role = member.role db_user_uid = [u.user_id for u in db_user] uid2name = {u.user_id: u.user_name for u in db_user} - create_list = [] - update_list = [] - delete_list = [] - for user_info in group_member_list: - user_id = str(user_info["user_id"]) - nickname = user_info["card"] or user_info["nickname"] - role = user_info["role"] - if ( - default_auth - and role in ["owner", "admin"] - and not await LevelUser.is_group_flag(user_id, group_id) + if member.id in driver.config.superusers: + await LevelUser.set_level(member.id, group_id, 9) + elif default_auth: + if role != "MEMBER" and not await LevelUser.is_group_flag( + member.id, group_id ): - if role == "owner": - await LevelUser.set_level(user_id, group_id, default_auth + 1) - else: - await LevelUser.set_level(user_id, group_id, default_auth) - if user_id in bot.config.superusers: - await LevelUser.set_level(user_id, group_id, 9) - join_time = datetime.fromtimestamp( - user_info["join_time"], timezone(timedelta(hours=8)) - ) - if cnt := db_user_uid.count(user_id): - users = [u for u in db_user if u.user_id == user_id] - if cnt > 1: - for u in users[1:]: - delete_list.append(u.id) - if nickname != uid2name.get(user_id): - user = users[0] - user.user_name = nickname - update_list.append(user) - else: - create_list.append( - GroupInfoUser( - user_id=user_id, - group_id=group_id, - user_name=nickname, - user_join_time=join_time, - platform="qq", - ) + if role == "OWNER": + await LevelUser.set_level(member.id, group_id, default_auth + 1) + elif role == "ADMINISTRATOR": + await LevelUser.set_level(member.id, group_id, default_auth) + if cnt := db_user_uid.count(member.id): + users = [u for u in db_user if u.user_id == member.id] + if cnt > 1: + for u in users[1:]: + data_list[2].append(u.id) + if nickname != uid2name.get(member.id): + user = users[0] + user.user_name = nickname + data_list[1].append(user) + else: + data_list[0].append( + GroupInfoUser( + user_id=member.id, + group_id=group_id, + user_name=nickname, + user_join_time=member.joined_at, + platform=platform, ) - exist_member_list.append(user_id) - if create_list: - await GroupInfoUser.bulk_create(create_list, 30) - logger.debug( - f"创建用户数据 {len(create_list)} 条", - "更新群组成员信息", - target=group_id, - ) - if update_list: - await GroupInfoUser.bulk_update(update_list, ["user_name"], 30) - logger.debug( - f"更新户数据 {len(update_list)} 条", "更新群组成员信息", target=group_id - ) - if delete_list: - await GroupInfoUser.filter(id__in=delete_list).delete() - logger.debug(f"删除重复数据 Ids: {delete_list}", "更新群组成员信息") - - if delete_member_list := [ - uid for uid in db_user_uid if uid not in exist_member_list - ]: - await GroupInfoUser.filter( - user_id__in=delete_member_list, group_id=group_id - ).delete() - logger.info( - f"删除已退群用户 {len(delete_member_list)} 条", - "更新群组成员信息", - group_id=group_id, - platform="qq", ) @classmethod - async def v12(cls, bot: v12Bot, group_id: str): - # TODO: v12更新群组成员信息 - pass - # exist_member_list = [] - # default_auth = Config.get_config("admin_bot_manage", "ADMIN_DEFAULT_AUTH") - # group_member_list: list[GetGroupMemberInfoResp] = - # await bot.get_group_member_list( - # group_id=group_id - # ) - # for user_info in group_member_list: - # user_id = user_info.user_id - # nickname = user_info.user_displayname or user_info.user_name - # role = user_info["role"] - # if default_auth: - # if role in ["owner", "admin"] and not LevelUser.is_group_flag( - # str(user_id), group_id - # ): - # await LevelUser.set_level(user_id, group_id, default_auth) - # if str(user_id) in bot.config.superusers: - # await LevelUser.set_level(str(user_id), group_id, 9) - # 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_id=str(user_id), - # group_id=group_id, - # defaults={ - # "user_name": nickname, - # "user_join_time": join_time.replace( - # tzinfo=timezone(timedelta(hours=8)) - # ), - # }, - # ) - # exist_member_list.append(str(user_id)) - # logger.debug("更新成功", "更新群组成员信息", - # session=user_id, group_id=group_id) - # if delete_member_list := list( - # set(exist_member_list).difference( - # set(await GroupInfoUser.get_group_member_id_list(group_id)) - # ) - # ): - # await GroupInfoUser.filter( - # user_id__in=delete_member_list, group_id=group_id - # ).delete() - # logger.info(f"删除已退群用户", "更新群组成员信息", group_id=group_id) + async def update_group_member(cls, bot: Bot, group_id: str) -> str: + """更新群组成员信息 + + 参数: + bot: Bot + group_id: 群组id + + 返回: + str: 返回消息 + """ + if not group_id: + logger.warning(f"bot: {bot.self_id},group_id为空,无法更新群成员信息...") + return "群组id为空..." + if interface := get_interface(bot): + scenes = await interface.get_scenes() + platform = PlatformUtils.get_platform(bot) + group_list = [s for s in scenes if s.is_group and s.id == group_id] + if not group_list: + logger.warning( + f"bot: {bot.self_id},group_id: {group_id},群组不存在," + "无法更新群成员信息..." + ) + return "更新群组失败,群组不存在..." + members = await interface.get_members(SceneType.GROUP, group_list[0].id) + db_user = await GroupInfoUser.filter(group_id=group_id).all() + db_user_uid = [u.user_id for u in db_user] + data_list = ([], [], []) + exist_member_list = [] + for member in members: + await cls.__handle_user(member, db_user, group_id, data_list, platform) + exist_member_list.append(member.id) + if data_list[0]: + await GroupInfoUser.bulk_create(data_list[0], 30) + logger.debug( + f"创建用户数据 {len(data_list[0])} 条", + "更新群组成员信息", + target=group_id, + ) + if data_list[1]: + await GroupInfoUser.bulk_update(data_list[1], ["user_name"], 30) + logger.debug( + f"更新户数据 {len(data_list[1])} 条", + "更新群组成员信息", + target=group_id, + ) + if data_list[2]: + await GroupInfoUser.filter(id__in=data_list[2]).delete() + logger.debug(f"删除重复数据 Ids: {data_list[2]}", "更新群组成员信息") + + if delete_member_list := [ + uid for uid in db_user_uid if uid not in exist_member_list + ]: + await GroupInfoUser.filter( + user_id__in=delete_member_list, group_id=group_id + ).delete() + logger.info( + f"删除已退群用户 {len(delete_member_list)} 条", + "更新群组成员信息", + group_id=group_id, + platform="qq", + ) + return "群组成员信息更新完成!" diff --git a/zhenxun/utils/platform.py b/zhenxun/utils/platform.py index a80ab6b7..859fd23c 100644 --- a/zhenxun/utils/platform.py +++ b/zhenxun/utils/platform.py @@ -7,10 +7,10 @@ import nonebot from pydantic import BaseModel from nonebot.adapters import Bot from nonebot.utils import is_coroutine_callable +from nonebot_plugin_uninfo import get_interface from nonebot.adapters.dodo import Bot as DodoBot from nonebot.adapters.onebot.v11 import Bot as v11Bot from nonebot.adapters.onebot.v12 import Bot as v12Bot -from nonebot.adapters.discord import Bot as DiscordBot from nonebot.adapters.kaiheila import Bot as KaiheilaBot from nonebot_plugin_alconna.uniseg import Target, Receipt, UniMessage @@ -380,13 +380,11 @@ class PlatformUtils: 返回: str | None: 平台 """ - if isinstance(bot, v11Bot | v12Bot): - return "qq" - if isinstance(bot, DodoBot): - return "dodo" - if isinstance(bot, KaiheilaBot): - return "kaiheila" - return "discord" if isinstance(bot, DiscordBot) else None + if interface := get_interface(bot): + info = interface.basic_info() + platform = info["scope"].lower() + return "qq" if platform.startswith("qq") else platform + return "unknown" @classmethod async def get_group_list(cls, bot: Bot) -> tuple[list[GroupConsole], str]: