feat(tag): 实现群组标签自动清理及手动清理功能

This commit is contained in:
webjoin111 2025-11-15 12:43:16 +08:00
parent c36c161b0e
commit 50c04f3625
4 changed files with 82 additions and 0 deletions

View File

@ -17,6 +17,8 @@ from zhenxun.configs.utils import PluginExtraData, RegisterConfig, Task
from zhenxun.models.event_log import EventLog from zhenxun.models.event_log import EventLog
from zhenxun.models.group_console import GroupConsole from zhenxun.models.group_console import GroupConsole
from zhenxun.services.cache import CacheRoot from zhenxun.services.cache import CacheRoot
from zhenxun.services.log import logger
from zhenxun.services.tags import tag_manager
from zhenxun.utils.common_utils import CommonUtils from zhenxun.utils.common_utils import CommonUtils
from zhenxun.utils.enum import EventLogType, PluginType from zhenxun.utils.enum import EventLogType, PluginType
from zhenxun.utils.platform import PlatformUtils from zhenxun.utils.platform import PlatformUtils
@ -135,6 +137,11 @@ async def _(
await EventLog.create( await EventLog.create(
user_id=user_id, group_id=group_id, event_type=EventLogType.KICK_BOT user_id=user_id, group_id=group_id, event_type=EventLogType.KICK_BOT
) )
await tag_manager.remove_group_from_all_tags(group_id)
logger.info(
f"机器人被移出群聊,已自动从所有静态标签中移除群组 {group_id}",
"群组标签管理",
)
elif event.sub_type in ["leave", "kick"]: elif event.sub_type in ["leave", "kick"]:
if event.sub_type == "leave": if event.sub_type == "leave":
"""主动退群""" """主动退群"""

View File

@ -2,6 +2,7 @@ import nonebot
from nonebot_plugin_apscheduler import scheduler from nonebot_plugin_apscheduler import scheduler
from zhenxun.services.log import logger from zhenxun.services.log import logger
from zhenxun.services.tags import tag_manager
from zhenxun.utils.platform import PlatformUtils from zhenxun.utils.platform import PlatformUtils
@ -37,3 +38,18 @@ async def _():
f"Bot: {bot.self_id} 自动更新好友信息错误", "自动更新好友", e=e f"Bot: {bot.self_id} 自动更新好友信息错误", "自动更新好友", e=e
) )
logger.info("自动更新好友信息成功...") logger.info("自动更新好友信息成功...")
# 自动清理静态标签中的无效群组
@scheduler.scheduled_job(
"cron",
hour=23,
minute=30,
)
async def _prune_stale_tags():
deleted_count = await tag_manager.prune_stale_group_links()
if deleted_count > 0:
logger.info(f"定时任务:成功清理了 {deleted_count} 个无效的群组标签"
f"关联。", "群组标签管理")
else:
logger.debug("定时任务:未发现无效的群组标签关联。", "群组标签管理")

View File

@ -176,6 +176,7 @@ tag_cmd = on_alconna(
help_text="删除标签", help_text="删除标签",
), ),
Subcommand("clear", help_text="清空所有标签"), Subcommand("clear", help_text="清空所有标签"),
Subcommand("prune", alias=["check", "清理"], help_text="清理无效的群组关联"),
Subcommand( Subcommand(
"clone", "clone",
Args["source_name", str]["new_name", str], Args["source_name", str]["new_name", str],
@ -192,6 +193,13 @@ tag_cmd = on_alconna(
block=True, block=True,
) )
tag_cmd.shortcut(
"清理标签",
command="tag",
arguments=["prune"],
prefix=True,
)
@tag_cmd.assign("list") @tag_cmd.assign("list")
async def handle_list(): async def handle_list():
@ -466,3 +474,10 @@ async def handle_clone(
await MessageUtils.build_message(msg).finish() await MessageUtils.build_message(msg).finish()
except (ValueError, IntegrityError) as e: except (ValueError, IntegrityError) as e:
await MessageUtils.build_message(f"克隆失败: {e}").finish() await MessageUtils.build_message(f"克隆失败: {e}").finish()
@tag_cmd.assign("prune")
async def handle_prune():
deleted_count = await tag_manager.prune_stale_group_links()
msg = f"清理完成!共移除了 {deleted_count} 个无效的群组关联。"
await MessageUtils.build_message(msg).finish()

View File

@ -9,6 +9,7 @@ from typing import Any, ClassVar
from aiocache import Cache, cached from aiocache import Cache, cached
from arclet.alconna import Alconna, Args from arclet.alconna import Alconna, Args
import nonebot
from nonebot.adapters import Bot from nonebot.adapters import Bot
from tortoise.exceptions import IntegrityError from tortoise.exceptions import IntegrityError
from tortoise.expressions import Q from tortoise.expressions import Q
@ -176,6 +177,49 @@ class TagManager:
deleted_count = await GroupTag.filter(name=name).delete() deleted_count = await GroupTag.filter(name=name).delete()
return deleted_count > 0 return deleted_count > 0
@invalidate_on_change
async def remove_group_from_all_tags(self, group_id: str) -> int:
"""
从所有静态标签中移除一个指定的群组ID
主要用于机器人退群时的实时清理
参数
group_id: 要移除的群组ID
返回
被删除的关联数量
"""
deleted_count = await GroupTagLink.filter(group_id=group_id).delete()
if deleted_count > 0:
logger.info(f"已从 {deleted_count} 个标签中移除群组 {group_id} 的关联。")
return deleted_count
@invalidate_on_change
async def prune_stale_group_links(self) -> int:
"""
清理所有静态标签中无效的群组关联
无效指的是机器人已不再任何一个已连接的Bot的群组列表中
返回
被清理的无效关联的总数
"""
all_bot_group_ids = set()
for bot in nonebot.get_bots().values():
groups, _ = await PlatformUtils.get_group_list(bot)
all_bot_group_ids.update(g.group_id for g in groups if g.group_id)
all_static_links = await GroupTagLink.filter(tag__tag_type="STATIC").all()
stale_link_ids = [
link.id
for link in all_static_links
if link.group_id not in all_bot_group_ids
]
if stale_link_ids:
return await GroupTagLink.filter(id__in=stale_link_ids).delete()
return 0
@invalidate_on_change @invalidate_on_change
async def add_groups_to_tag(self, name: str, group_ids: list[str]) -> int: # type: ignore async def add_groups_to_tag(self, name: str, group_ids: list[str]) -> int: # type: ignore
""" """