mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-09 13:50:00 +08:00
版本更新
This commit is contained in:
@@ -1,34 +1,53 @@
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
import nonebot
|
||||
import ujson as json
|
||||
from nonebot import require
|
||||
from nonebot.drivers import Driver
|
||||
from tortoise import Tortoise
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.drivers import Driver
|
||||
from tortoise.exceptions import OperationalError
|
||||
|
||||
from zhenxun.models.goods_info import GoodsInfo
|
||||
from zhenxun.models.group_member_info import GroupInfoUser
|
||||
from zhenxun.models.sign_user import SignUser
|
||||
from zhenxun.models.user_console import UserConsole
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils.decorator.shop import shop_register
|
||||
|
||||
require("nonebot_plugin_apscheduler")
|
||||
require("nonebot_plugin_alconna")
|
||||
require("nonebot_plugin_session")
|
||||
require("nonebot_plugin_userinfo")
|
||||
require("nonebot_plugin_htmlrender")
|
||||
# require("nonebot_plugin_uninfo")
|
||||
|
||||
|
||||
import nonebot
|
||||
import ujson as json
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.models.sign_user import SignUser
|
||||
from zhenxun.models.goods_info import GoodsInfo
|
||||
from zhenxun.models.user_console import UserConsole
|
||||
from zhenxun.utils.decorator.shop import shop_register
|
||||
from zhenxun.models.bot_connect_log import BotConnectLog
|
||||
from zhenxun.models.group_member_info import GroupInfoUser
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
@driver.on_bot_connect
|
||||
async def _(bot: Bot):
|
||||
logger.debug(f"Bot: {bot.self_id} 建立连接...")
|
||||
await BotConnectLog.create(
|
||||
bot_id=bot.self_id, platform=bot.adapter, connect_time=datetime.now(), type=1
|
||||
)
|
||||
|
||||
|
||||
@driver.on_bot_disconnect
|
||||
async def _(bot: Bot):
|
||||
logger.debug(f"Bot: {bot.self_id} 断开连接...")
|
||||
await BotConnectLog.create(
|
||||
bot_id=bot.self_id, platform=bot.adapter, connect_time=datetime.now(), type=0
|
||||
)
|
||||
|
||||
|
||||
SIGN_SQL = """
|
||||
select distinct on("user_id") t1.user_id, t1.checkin_count, t1.add_probability, t1.specify_probability, t1.impression
|
||||
select distinct on("user_id") t1.user_id, t1.checkin_count, t1.add_probability,
|
||||
t1.specify_probability, t1.impression
|
||||
from public.sign_group_users t1
|
||||
join (
|
||||
join (
|
||||
select user_id, max(t2.impression) as max_impression
|
||||
from public.sign_group_users t2
|
||||
group by user_id
|
||||
@@ -38,7 +57,7 @@ from public.sign_group_users t1
|
||||
BAG_SQL = """
|
||||
select t1.user_id, t1.gold, t1.property
|
||||
from public.bag_users t1
|
||||
join (
|
||||
join (
|
||||
select user_id, max(t2.gold) as max_gold
|
||||
from public.bag_users t2
|
||||
group by user_id
|
||||
@@ -74,15 +93,12 @@ async def _():
|
||||
}
|
||||
create_list = []
|
||||
sign_id_list = []
|
||||
max_uid = 0
|
||||
if user2uid:
|
||||
max_uid = max(user2uid.values()) + 1
|
||||
max_uid = max(user2uid.values()) + 1 if user2uid else 0
|
||||
for old_sign in old_sign_list:
|
||||
sign_id_list.append(old_sign["user_id"])
|
||||
old_bag = [
|
||||
if old_bag := [
|
||||
b for b in old_bag_list if b["user_id"] == old_sign["user_id"]
|
||||
]
|
||||
if old_bag:
|
||||
]:
|
||||
old_bag = old_bag[0]
|
||||
property = json.loads(old_bag["property"])
|
||||
props = {}
|
||||
@@ -115,9 +131,9 @@ async def _():
|
||||
create_list.clear()
|
||||
uc_dict = {u.user_id: u for u in await UserConsole.all()}
|
||||
for old_sign in old_sign_list:
|
||||
user_console = uc_dict.get(old_sign["user_id"])
|
||||
if not user_console:
|
||||
user_console = await UserConsole.get_user(old_sign["user_id"], "qq")
|
||||
user_console = uc_dict.get(
|
||||
old_sign["user_id"]
|
||||
) or await UserConsole.get_user(old_sign["user_id"], "qq")
|
||||
create_list.append(
|
||||
SignUser(
|
||||
user_id=old_sign["user_id"],
|
||||
|
||||
@@ -2,12 +2,14 @@ from pathlib import Path
|
||||
|
||||
import aiofiles
|
||||
from nonebot.rule import to_me
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from nonebot.plugin import PluginMetadata
|
||||
from nonebot_plugin_session import EventSession
|
||||
from nonebot_plugin_alconna import Alconna, Arparma, on_alconna
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils.message import MessageUtils
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
from zhenxun.configs.path_config import DATA_PATH
|
||||
from zhenxun.configs.utils import PluginExtraData
|
||||
|
||||
__plugin_meta__ = PluginMetadata(
|
||||
@@ -25,19 +27,33 @@ _matcher = on_alconna(Alconna("关于"), priority=5, block=True, rule=to_me())
|
||||
|
||||
|
||||
@_matcher.handle()
|
||||
async def _(session: EventSession, arparma: Arparma):
|
||||
async def _(session: Uninfo, arparma: Arparma):
|
||||
ver_file = Path() / "__version__"
|
||||
version = None
|
||||
if ver_file.exists():
|
||||
async with aiofiles.open(ver_file, encoding="utf8") as f:
|
||||
if text := await f.read():
|
||||
version = text.split(":")[-1].strip()
|
||||
info = f"""
|
||||
if PlatformUtils.is_qbot(session):
|
||||
info: list[str | Path] = [
|
||||
f"""
|
||||
『绪山真寻Bot』
|
||||
版本:{version}
|
||||
简介:基于Nonebot2开发,支持多平台,是一个非常可爱的Bot呀,希望与大家要好好相处
|
||||
""".strip()
|
||||
]
|
||||
path = DATA_PATH / "about.png"
|
||||
if path.exists():
|
||||
info.append(path)
|
||||
else:
|
||||
info = [
|
||||
f"""
|
||||
『绪山真寻Bot』
|
||||
版本:{version}
|
||||
简介:基于Nonebot2开发,支持多平台,是一个非常可爱的Bot呀,希望与大家要好好相处
|
||||
项目地址:https://github.com/HibiKier/zhenxun_bot
|
||||
文档地址:https://hibikier.github.io/zhenxun_bot/
|
||||
""".strip()
|
||||
await MessageUtils.build_message(info).send()
|
||||
""".strip()
|
||||
]
|
||||
await MessageUtils.build_message(info).send() # type: ignore
|
||||
logger.info("查看关于", arparma.header_result, session=session)
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
from nonebot import on_notice
|
||||
from nonebot.adapters.onebot.v11 import GroupAdminNoticeEvent
|
||||
from nonebot.plugin import PluginMetadata
|
||||
from nonebot.adapters.onebot.v11 import GroupAdminNoticeEvent
|
||||
|
||||
from zhenxun.configs.config import Config
|
||||
from zhenxun.configs.utils import PluginExtraData, RegisterConfig
|
||||
from zhenxun.models.level_user import LevelUser
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.configs.config import Config
|
||||
from zhenxun.utils.enum import PluginType
|
||||
from zhenxun.utils.rules import notice_rule
|
||||
from zhenxun.models.level_user import LevelUser
|
||||
from zhenxun.configs.utils import RegisterConfig, PluginExtraData
|
||||
|
||||
__plugin_meta__ = PluginMetadata(
|
||||
name="群管理员变动监测",
|
||||
description="检测群管理员变动, 添加与删除管理员默认权限, 当配置项 ADMIN_DEFAULT_AUTH 为空时, 不会添加管理员权限",
|
||||
description="""检测群管理员变动, 添加与删除管理员默认权限,
|
||||
当配置项 ADMIN_DEFAULT_AUTH 为空时, 不会添加管理员权限""",
|
||||
usage="",
|
||||
extra=PluginExtraData(
|
||||
author="HibiKier",
|
||||
@@ -29,7 +31,7 @@ __plugin_meta__ = PluginMetadata(
|
||||
)
|
||||
|
||||
|
||||
admin_notice = on_notice(priority=5)
|
||||
admin_notice = on_notice(priority=5, rule=notice_rule(GroupAdminNoticeEvent))
|
||||
|
||||
base_config = Config.get("admin_bot_manage")
|
||||
|
||||
@@ -52,7 +54,8 @@ async def _(event: GroupAdminNoticeEvent):
|
||||
)
|
||||
else:
|
||||
logger.warning(
|
||||
f"配置项 MODULE: [<u><y>admin_bot_manage</y></u>] | KEY: [<u><y>ADMIN_DEFAULT_AUTH</y></u>] 为空"
|
||||
"配置项 MODULE: [<u><y>admin_bot_manage</y></u>] |"
|
||||
" KEY: [<u><y>ADMIN_DEFAULT_AUTH</y></u>] 为空"
|
||||
)
|
||||
elif event.sub_type == "unset":
|
||||
await LevelUser.delete_level(str(event.user_id), str(event.group_id))
|
||||
|
||||
@@ -30,7 +30,7 @@ __plugin_meta__ = PluginMetadata(
|
||||
usage="""
|
||||
普通管理员
|
||||
格式:
|
||||
ban [At用户] -t [时长(分钟)]
|
||||
ban [At用户] ?[-t [时长(分钟)]]
|
||||
|
||||
示例:
|
||||
ban @用户 : 永久拉黑用户
|
||||
@@ -44,7 +44,8 @@ __plugin_meta__ = PluginMetadata(
|
||||
superuser_help="""
|
||||
超级管理员额外命令
|
||||
格式:
|
||||
ban [At用户/用户Id] [时长]
|
||||
ban [At用户/用户Id] ?[-t [时长]]
|
||||
unban --id [idx] : 通过id来进行unban操作
|
||||
ban列表: 获取所有Ban数据
|
||||
|
||||
群组ban列表: 获取群组Ban数据
|
||||
@@ -98,6 +99,7 @@ _unban_matcher = on_alconna(
|
||||
"unban",
|
||||
Args["user?", [str, At]],
|
||||
Option("-g|--group", Args["group_id", str]),
|
||||
Option("--id", Args["idx", int]),
|
||||
),
|
||||
rule=admin_check("ban", "BAN_LEVEL"),
|
||||
priority=5,
|
||||
@@ -238,8 +240,10 @@ async def _(
|
||||
arparma: Arparma,
|
||||
user: Match[str | At],
|
||||
group_id: Match[str],
|
||||
idx: Match[int],
|
||||
):
|
||||
user_id = ""
|
||||
_idx = idx.result if idx.available else None
|
||||
if user.available:
|
||||
if isinstance(user.result, At):
|
||||
user_id = user.result.target
|
||||
@@ -248,48 +252,44 @@ async def _(
|
||||
await MessageUtils.build_message("权限不足捏...").finish(reply_to=True)
|
||||
user_id = user.result
|
||||
if gid := session.id3 or session.id2:
|
||||
u_d = user_id
|
||||
if group_id.available:
|
||||
u_d = gid
|
||||
gid = group_id.result
|
||||
if await BanManage.unban(
|
||||
user_id, gid, session, session.id1 in bot.config.superusers
|
||||
):
|
||||
logger.info(
|
||||
"管理员UnBan",
|
||||
arparma.header_result,
|
||||
session=session,
|
||||
target=f"{gid}:{user_id}",
|
||||
)
|
||||
await MessageUtils.build_message(
|
||||
[
|
||||
"将 ",
|
||||
(
|
||||
At(flag="user", target=user_id)
|
||||
if isinstance(user.result, At)
|
||||
else u_d
|
||||
), # type: ignore
|
||||
" 从黑屋中拉了出来并急救了一下!",
|
||||
]
|
||||
).finish(reply_to=True)
|
||||
else:
|
||||
await MessageUtils.build_message("该用户不在黑名单中捏...").finish(
|
||||
reply_to=True
|
||||
)
|
||||
is_unban, result = await BanManage.unban(
|
||||
user_id, gid, session, _idx, session.id1 in bot.config.superusers
|
||||
)
|
||||
if not is_unban:
|
||||
await MessageUtils.build_message(result).finish(reply_to=True)
|
||||
logger.info(
|
||||
"管理员UnBan",
|
||||
arparma.header_result,
|
||||
session=session,
|
||||
target=f"{gid}:{result}",
|
||||
)
|
||||
await MessageUtils.build_message(
|
||||
[
|
||||
"将 ",
|
||||
(
|
||||
At(flag="user", target=user_id)
|
||||
if isinstance(user.result, At)
|
||||
else result
|
||||
), # type: ignore
|
||||
" 从黑屋中拉了出来并急救了一下!",
|
||||
]
|
||||
).finish(reply_to=True)
|
||||
elif session.id1 in bot.config.superusers:
|
||||
_group_id = group_id.result if group_id.available else None
|
||||
if await BanManage.unban(user_id, _group_id, session, True):
|
||||
logger.info(
|
||||
"超级用户UnBan",
|
||||
arparma.header_result,
|
||||
session=session,
|
||||
target=f"{_group_id}:{user_id}",
|
||||
)
|
||||
at_msg = user_id or f"群组:{_group_id}"
|
||||
await MessageUtils.build_message(
|
||||
f"对 {at_msg} 从黑屋中拉了出来并急救了一下!"
|
||||
).finish(reply_to=True)
|
||||
else:
|
||||
await MessageUtils.build_message("该用户不在黑名单中捏...").finish(
|
||||
reply_to=True
|
||||
)
|
||||
is_unban, result = await BanManage.unban(
|
||||
user_id, _group_id, session, _idx, True
|
||||
)
|
||||
if not is_unban:
|
||||
await MessageUtils.build_message(result).finish(reply_to=True)
|
||||
logger.info(
|
||||
"超级用户UnBan",
|
||||
arparma.header_result,
|
||||
session=session,
|
||||
target=f"{_group_id}:{user_id}",
|
||||
)
|
||||
at_msg = user_id or f"群组:{result}"
|
||||
await MessageUtils.build_message(
|
||||
f"对 {at_msg} 从黑屋中拉了出来并急救了一下!"
|
||||
).finish(reply_to=True)
|
||||
|
||||
@@ -32,11 +32,10 @@ class BanManage:
|
||||
query = query.filter(user_id=user_id)
|
||||
elif group_id:
|
||||
query = query.filter(group_id=group_id)
|
||||
else:
|
||||
if filter_type == "user":
|
||||
query = query.filter(group_id__isnull=True)
|
||||
elif filter_type == "group":
|
||||
query = query.filter(user_id__isnull=True)
|
||||
elif filter_type == "user":
|
||||
query = query.filter(group_id__isnull=True)
|
||||
elif filter_type == "group":
|
||||
query = query.filter(user_id__isnull=True)
|
||||
data_list = await query.all()
|
||||
if not data_list:
|
||||
return None
|
||||
@@ -85,26 +84,36 @@ class BanManage:
|
||||
user_id: str | None,
|
||||
group_id: str | None,
|
||||
session: EventSession,
|
||||
idx: int | None = None,
|
||||
is_superuser: bool = False,
|
||||
) -> bool:
|
||||
) -> tuple[bool, str]:
|
||||
"""unban目标用户
|
||||
|
||||
参数:
|
||||
user_id: 用户id
|
||||
group_id: 群组id
|
||||
session: Session
|
||||
idx: 指定id
|
||||
is_superuser: 是否为超级用户操作
|
||||
|
||||
返回:
|
||||
bool: 是否unban成功
|
||||
tuple[bool, str]: 是否unban成功, 群组/用户id或提示
|
||||
"""
|
||||
user_level = 9999
|
||||
if not is_superuser and user_id and session.id1:
|
||||
user_level = await LevelUser.get_user_level(session.id1, group_id)
|
||||
if await BanConsole.check_ban_level(user_id, group_id, user_level):
|
||||
if idx:
|
||||
ban_data = await BanConsole.get_or_none(id=idx)
|
||||
if not ban_data:
|
||||
return False, "该用户/群组不在黑名单中不足捏..."
|
||||
if ban_data.ban_level > user_level:
|
||||
return False, "unBan权限等级不足捏..."
|
||||
await ban_data.delete()
|
||||
return True, str(ban_data.user_id or ban_data.group_id)
|
||||
elif await BanConsole.check_ban_level(user_id, group_id, user_level):
|
||||
await BanConsole.unban(user_id, group_id)
|
||||
return True
|
||||
return False
|
||||
return True, str(group_id)
|
||||
return False, "该用户/群组不在黑名单中不足捏..."
|
||||
|
||||
@classmethod
|
||||
async def ban(
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import nonebot
|
||||
from nonebot import on_notice
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.adapters.onebot.v11 import GroupIncreaseNoticeEvent
|
||||
from nonebot.plugin import PluginMetadata
|
||||
from nonebot_plugin_alconna import Alconna, Arparma, on_alconna
|
||||
from nonebot_plugin_apscheduler import scheduler
|
||||
from nonebot_plugin_session import EventSession
|
||||
from nonebot_plugin_apscheduler import scheduler
|
||||
from nonebot_plugin_alconna import Alconna, Arparma, on_alconna
|
||||
from nonebot.adapters.onebot.v11 import GroupIncreaseNoticeEvent
|
||||
|
||||
from zhenxun.configs.config import BotConfig
|
||||
from zhenxun.configs.utils import PluginExtraData
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils.enum import PluginType
|
||||
from zhenxun.configs.config import BotConfig
|
||||
from zhenxun.utils.message import MessageUtils
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
from zhenxun.utils.rules import admin_check, ensure_group
|
||||
from zhenxun.configs.utils import PluginExtraData
|
||||
from zhenxun.utils.rules import admin_check, notice_rule, ensure_group
|
||||
|
||||
from ._data_source import MemberUpdateManage
|
||||
|
||||
@@ -42,25 +42,22 @@ _matcher = on_alconna(
|
||||
)
|
||||
|
||||
|
||||
_notice = on_notice(priority=1, block=False)
|
||||
_notice = on_notice(priority=1, block=False, rule=notice_rule(GroupIncreaseNoticeEvent))
|
||||
|
||||
|
||||
@_matcher.handle()
|
||||
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(
|
||||
|
||||
@@ -1,213 +1,132 @@
|
||||
from datetime import datetime, timezone, timedelta
|
||||
from datetime import datetime
|
||||
|
||||
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 role and default_auth:
|
||||
if role.id != "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.id == "OWNER":
|
||||
await LevelUser.set_level(member.id, group_id, default_auth + 1)
|
||||
elif role.id == "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 or datetime.now(),
|
||||
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:
|
||||
logger.debug(f"即将更新群组成员: {member}", "更新群组成员信息")
|
||||
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 "群组成员信息更新完成!"
|
||||
|
||||
@@ -133,7 +133,7 @@ async def build_task(group_id: str | None) -> BuildImage:
|
||||
task.id,
|
||||
task.module,
|
||||
task.name,
|
||||
"开启" if task.module not in group.block_task else "关闭",
|
||||
"开启" if f"<{task.module}," not in group.block_task else "关闭",
|
||||
"开启" if task.status else "关闭",
|
||||
task.run_time or "-",
|
||||
]
|
||||
@@ -211,12 +211,10 @@ class PluginManage:
|
||||
if status:
|
||||
for module in module_list:
|
||||
group.block_plugin = group.block_plugin.replace(
|
||||
f"{module},", ""
|
||||
f"<{module},", ""
|
||||
)
|
||||
else:
|
||||
module_list = await PluginInfo.filter(
|
||||
plugin_type=PluginType.NORMAL
|
||||
).values_list("module", flat=True)
|
||||
module_list = [f"<{module}" for module in module_list]
|
||||
group.block_plugin = ",".join(module_list) + "," # type: ignore
|
||||
await group.save(update_fields=["block_plugin"])
|
||||
return f'成功将此群组所有功能状态修改为: {"开启" if status else "关闭"}'
|
||||
@@ -413,7 +411,7 @@ class PluginManage:
|
||||
参数:
|
||||
task_name: 被动技能名称
|
||||
group_id: 群组Id
|
||||
status: 状态
|
||||
status: 状态,为True时是关闭
|
||||
is_all: 所有群被动
|
||||
|
||||
返回:
|
||||
@@ -426,6 +424,7 @@ class PluginManage:
|
||||
group, _ = await GroupConsole.get_or_create(
|
||||
group_id=group_id, channel_id__isnull=True
|
||||
)
|
||||
modules = [f"<{module}" for module in modules]
|
||||
if status:
|
||||
group.block_task = ",".join(modules) + "," # type: ignore
|
||||
else:
|
||||
@@ -434,16 +433,12 @@ class PluginManage:
|
||||
await group.save(update_fields=["block_task"])
|
||||
return f"已成功{status_str}全部被动技能!"
|
||||
elif task := await TaskInfo.get_or_none(name=task_name):
|
||||
group, _ = await GroupConsole.get_or_create(
|
||||
group_id=group_id, channel_id__isnull=True
|
||||
)
|
||||
if status:
|
||||
group.block_task += f"{task.module},"
|
||||
elif f"super:{task.module}," in group.block_task:
|
||||
await GroupConsole.set_block_task(group_id, task.module)
|
||||
elif await GroupConsole.is_superuser_block_task(group_id, task.module):
|
||||
return f"{status_str} {task_name} 被动技能失败,当前群组该被动已被管理员禁用" # noqa: E501
|
||||
else:
|
||||
group.block_task = group.block_task.replace(f"{task.module},", "")
|
||||
await group.save(update_fields=["block_task"])
|
||||
await GroupConsole.set_unblock_task(group_id, task.module)
|
||||
return f"已成功{status_str} {task_name} 被动技能!"
|
||||
return "没有找到这个被动技能喔..."
|
||||
|
||||
@@ -469,20 +464,13 @@ class PluginManage:
|
||||
name=plugin_name, load_status=True, plugin_type__not=PluginType.PARENT
|
||||
)
|
||||
if plugin:
|
||||
group, _ = await GroupConsole.get_or_create(
|
||||
group_id=group_id, channel_id__isnull=True
|
||||
)
|
||||
status_str = "开启" if status else "关闭"
|
||||
if status:
|
||||
if plugin.module in group.block_plugin:
|
||||
group.block_plugin = group.block_plugin.replace(
|
||||
f"{plugin.module},", ""
|
||||
)
|
||||
await group.save(update_fields=["block_plugin"])
|
||||
if await GroupConsole.is_normal_block_plugin(group_id, plugin.module):
|
||||
await GroupConsole.set_unblock_plugin(group_id, plugin.module)
|
||||
return f"已成功{status_str} {plugin.name} 功能!"
|
||||
elif plugin.module not in group.block_plugin:
|
||||
group.block_plugin += f"{plugin.module},"
|
||||
await group.save(update_fields=["block_plugin"])
|
||||
elif not await GroupConsole.is_normal_block_plugin(group_id, plugin.module):
|
||||
await GroupConsole.set_block_plugin(group_id, plugin.module)
|
||||
return f"已成功{status_str} {plugin.name} 功能!"
|
||||
return f"该功能已经{status_str}了喔,不要重复{status_str}..."
|
||||
return "没有找到这个功能喔..."
|
||||
@@ -504,14 +492,10 @@ class PluginManage:
|
||||
if not (task := await TaskInfo.get_or_none(name=task_name)):
|
||||
return "没有找到这个功能喔..."
|
||||
if group_id:
|
||||
group, _ = await GroupConsole.get_or_create(
|
||||
group_id=group_id, channel_id__isnull=True
|
||||
)
|
||||
if status:
|
||||
group.block_task = group.block_task.replace(f"super:{task.module},", "")
|
||||
await GroupConsole.set_unblock_task(group_id, task.module, True)
|
||||
else:
|
||||
group.block_task += f"super:{task.module},"
|
||||
await group.save(update_fields=["block_task"])
|
||||
await GroupConsole.set_block_task(group_id, task.module, True)
|
||||
status_str = "开启" if status else "关闭"
|
||||
return f"已成功将群组 {group_id} 被动技能 {task_name} {status_str}!"
|
||||
return "没有找到这个群组喔..."
|
||||
@@ -538,17 +522,12 @@ class PluginManage:
|
||||
)
|
||||
if plugin:
|
||||
if group_id:
|
||||
if group := await GroupConsole.get_or_none(
|
||||
group_id=group_id, channel_id__isnull=True
|
||||
if not await GroupConsole.is_superuser_block_plugin(
|
||||
group_id, plugin.module
|
||||
):
|
||||
if f"super:{plugin.module}," not in group.block_plugin:
|
||||
group.block_plugin += f"super:{plugin.module},"
|
||||
await group.save(update_fields=["block_plugin"])
|
||||
return (
|
||||
f"已成功关闭群组 {group.group_name} 的 {plugin_name} 功能!"
|
||||
)
|
||||
return "此群组该功能已被超级用户关闭,不要重复关闭..."
|
||||
return "群组信息未更新,请先更新群组信息..."
|
||||
await GroupConsole.set_block_plugin(group_id, plugin.module, True)
|
||||
return f"已成功关闭群组 {group_id} 的 {plugin_name} 功能!"
|
||||
return "此群组该功能已被超级用户关闭,不要重复关闭..."
|
||||
plugin.block_type = block_type
|
||||
plugin.status = not bool(block_type)
|
||||
await plugin.save(update_fields=["status", "block_type"])
|
||||
@@ -584,19 +563,12 @@ class PluginManage:
|
||||
)
|
||||
if plugin:
|
||||
if group_id:
|
||||
if group := await GroupConsole.get_or_none(
|
||||
group_id=group_id, channel_id__isnull=True
|
||||
if await GroupConsole.is_superuser_block_plugin(
|
||||
group_id, plugin.module
|
||||
):
|
||||
if f"super:{plugin.module}," in group.block_plugin:
|
||||
group.block_plugin = group.block_plugin.replace(
|
||||
f"super:{plugin.module},", ""
|
||||
)
|
||||
await group.save(update_fields=["block_plugin"])
|
||||
return (
|
||||
f"已成功开启群组 {group.group_name} 的 {plugin_name} 功能!"
|
||||
)
|
||||
return "此群组该功能已被超级用户开启,不要重复开启..."
|
||||
return "群组信息未更新,请先更新群组信息..."
|
||||
await GroupConsole.set_unblock_plugin(group_id, plugin.module, True)
|
||||
return f"已成功开启群组 {group_id} 的 {plugin_name} 功能!"
|
||||
return "此群组该功能已被超级用户开启,不要重复开启..."
|
||||
plugin.block_type = block_type
|
||||
plugin.status = not bool(block_type)
|
||||
await plugin.save(update_fields=["status", "block_type"])
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from nonebot.rule import to_me
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from nonebot.plugin import PluginMetadata
|
||||
from nonebot_plugin_session import EventSession
|
||||
from nonebot_plugin_alconna import (
|
||||
Args,
|
||||
Match,
|
||||
@@ -58,28 +58,26 @@ _matcher = on_alconna(
|
||||
async def _(
|
||||
bot: Bot,
|
||||
name: Match[str],
|
||||
session: EventSession,
|
||||
session: Uninfo,
|
||||
is_superuser: Query[bool] = AlconnaQuery("superuser.value", False),
|
||||
):
|
||||
if not session.id1:
|
||||
await MessageUtils.build_message("用户id为空...").finish()
|
||||
_is_superuser = is_superuser.result if is_superuser.available else False
|
||||
if name.available:
|
||||
if _is_superuser and session.id1 not in bot.config.superusers:
|
||||
if _is_superuser and session.user.id not in bot.config.superusers:
|
||||
_is_superuser = False
|
||||
if result := await get_plugin_help(session.id1, name.result, _is_superuser):
|
||||
if result := await get_plugin_help(session.user.id, name.result, _is_superuser):
|
||||
await MessageUtils.build_message(result).send(reply_to=True)
|
||||
else:
|
||||
await MessageUtils.build_message("没有此功能的帮助信息...").send(
|
||||
reply_to=True
|
||||
)
|
||||
logger.info(f"查看帮助详情: {name.result}", "帮助", session=session)
|
||||
elif gid := session.id3 or session.id2:
|
||||
elif session.group and (gid := session.group.id):
|
||||
_image_path = GROUP_HELP_PATH / f"{gid}.png"
|
||||
if not _image_path.exists():
|
||||
await create_help_img(bot.self_id, gid, session.platform)
|
||||
await create_help_img(session, gid)
|
||||
await MessageUtils.build_message(_image_path).finish()
|
||||
else:
|
||||
if not SIMPLE_HELP_IMAGE.exists():
|
||||
await create_help_img(bot.self_id, None, session.platform)
|
||||
await create_help_img(session, None)
|
||||
await MessageUtils.build_message(SIMPLE_HELP_IMAGE).finish()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import nonebot
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
|
||||
from zhenxun.utils.enum import PluginType
|
||||
from zhenxun.models.level_user import LevelUser
|
||||
@@ -19,19 +20,18 @@ background = IMAGE_PATH / "background" / "0.png"
|
||||
driver = nonebot.get_driver()
|
||||
|
||||
|
||||
async def create_help_img(bot_id: str, group_id: str | None, platform: str):
|
||||
async def create_help_img(session: Uninfo, group_id: str | None):
|
||||
"""生成帮助图片
|
||||
|
||||
参数:
|
||||
bot_id: bot id
|
||||
session: Uninfo
|
||||
group_id: 群号
|
||||
platform: 平台
|
||||
"""
|
||||
help_type: str = base_config.get("type")
|
||||
if help_type.lower() == "html":
|
||||
result = BuildImage.open(await build_html_image(group_id))
|
||||
elif help_type.lower() == "zhenxun":
|
||||
result = BuildImage.open(await build_zhenxun_image(bot_id, group_id, platform))
|
||||
result = BuildImage.open(await build_zhenxun_image(session, group_id))
|
||||
else:
|
||||
result = await build_normal_image(group_id)
|
||||
if group_id:
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
from pydantic import BaseModel
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from nonebot_plugin_htmlrender import template_to_pic
|
||||
|
||||
from zhenxun.utils.enum import BlockType
|
||||
from zhenxun.configs.config import BotConfig
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
from zhenxun.models.plugin_info import PluginInfo
|
||||
from zhenxun.configs.path_config import TEMPLATE_PATH
|
||||
@@ -60,12 +62,21 @@ def build_plugin_data(classify: dict[str, list[Item]]) -> list[dict[str, str]]:
|
||||
for menu, value in classify.items()
|
||||
]
|
||||
plugin_list = build_line_data(plugin_list)
|
||||
plugin_list.insert(0, build_plugin_line(menu_key, max_data, 30, 100))
|
||||
plugin_list.insert(
|
||||
0,
|
||||
build_plugin_line(
|
||||
menu_key if menu_key not in ["normal", "功能"] else "主要功能",
|
||||
max_data,
|
||||
30,
|
||||
100,
|
||||
True,
|
||||
),
|
||||
)
|
||||
return plugin_list
|
||||
|
||||
|
||||
def build_plugin_line(
|
||||
name: str, items: list, left: int, width: int | None = None
|
||||
name: str, items: list, left: int, width: int | None = None, is_max: bool = False
|
||||
) -> dict:
|
||||
"""构造插件行数据
|
||||
|
||||
@@ -74,13 +85,14 @@ def build_plugin_line(
|
||||
items: 插件名称列表
|
||||
left: 左边距
|
||||
width: 总插件长度.
|
||||
is_max: 是否为最大长度的插件菜单
|
||||
|
||||
返回:
|
||||
dict: 插件数据
|
||||
"""
|
||||
_plugins = []
|
||||
width = width or 50
|
||||
if len(items) // 2 > 6:
|
||||
if len(items) // 2 > 6 or is_max:
|
||||
width = 100
|
||||
plugin_list1 = []
|
||||
plugin_list2 = []
|
||||
@@ -113,25 +125,25 @@ def build_line_data(plugin_list: list[dict]) -> list[dict]:
|
||||
return data
|
||||
|
||||
|
||||
async def build_zhenxun_image(
|
||||
bot_id: str, group_id: str | None, platform: str
|
||||
) -> bytes:
|
||||
async def build_zhenxun_image(session: Uninfo, group_id: str | None) -> bytes:
|
||||
"""构造真寻帮助图片
|
||||
|
||||
参数:
|
||||
bot_id: bot_id
|
||||
group_id: 群号
|
||||
platform: 平台
|
||||
"""
|
||||
classify = await classify_plugin(group_id, __handle_item)
|
||||
plugin_list = build_plugin_data(classify)
|
||||
platform = PlatformUtils.get_platform(session)
|
||||
bot_id = BotConfig.get_qbot_uid(session.self_id) or session.self_id
|
||||
bot_ava = PlatformUtils.get_user_avatar_url(bot_id, platform)
|
||||
return await template_to_pic(
|
||||
template_path=str((TEMPLATE_PATH / "ss_menu").absolute()),
|
||||
template_name="main.html",
|
||||
templates={
|
||||
"data": {
|
||||
"plugin_list": plugin_list,
|
||||
"ava": PlatformUtils.get_user_avatar_url(bot_id, platform),
|
||||
"ava": bot_ava,
|
||||
}
|
||||
},
|
||||
pages={
|
||||
|
||||
@@ -88,7 +88,7 @@ class LimitManage:
|
||||
@classmethod
|
||||
async def check(
|
||||
cls,
|
||||
module_path: str,
|
||||
module: str,
|
||||
user_id: str,
|
||||
group_id: str | None,
|
||||
channel_id: str | None,
|
||||
@@ -106,11 +106,11 @@ class LimitManage:
|
||||
异常:
|
||||
IgnoredException: IgnoredException
|
||||
"""
|
||||
if limit_model := cls.cd_limit.get(module_path):
|
||||
if limit_model := cls.cd_limit.get(module):
|
||||
await cls.__check(limit_model, user_id, group_id, channel_id, session)
|
||||
if limit_model := cls.block_limit.get(module_path):
|
||||
if limit_model := cls.block_limit.get(module):
|
||||
await cls.__check(limit_model, user_id, group_id, channel_id, session)
|
||||
if limit_model := cls.count_limit.get(module_path):
|
||||
if limit_model := cls.count_limit.get(module):
|
||||
await cls.__check(limit_model, user_id, group_id, channel_id, session)
|
||||
|
||||
@classmethod
|
||||
@@ -298,7 +298,7 @@ class AuthChecker:
|
||||
LimitManage.add_limit(limit)
|
||||
if user_id:
|
||||
await LimitManage.check(
|
||||
plugin.module_path, user_id, group_id, channel_id, session
|
||||
plugin.module, user_id, group_id, channel_id, session
|
||||
)
|
||||
|
||||
async def auth_plugin(
|
||||
@@ -319,8 +319,8 @@ class AuthChecker:
|
||||
is_poke = isinstance(event, PokeNotifyEvent)
|
||||
if group_id:
|
||||
sid = group_id or user_id
|
||||
if await GroupConsole.is_super_block_plugin(
|
||||
group_id, plugin.module, channel_id
|
||||
if await GroupConsole.is_superuser_block_plugin(
|
||||
group_id, plugin.module
|
||||
):
|
||||
"""超级用户群组插件状态"""
|
||||
if self.is_send_limit_message(plugin, sid) and not is_poke:
|
||||
@@ -334,9 +334,7 @@ class AuthChecker:
|
||||
session=session,
|
||||
)
|
||||
raise IgnoredException("超级管理员禁用了该群此功能...")
|
||||
if await GroupConsole.is_block_plugin(
|
||||
group_id, plugin.module, channel_id
|
||||
):
|
||||
if await GroupConsole.is_normal_block_plugin(group_id, plugin.module):
|
||||
"""群组插件状态"""
|
||||
if self.is_send_limit_message(plugin, sid) and not is_poke:
|
||||
self._flmt_s.start_cd(group_id or user_id)
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import logging
|
||||
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.exception import IgnoredException
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_preprocessor
|
||||
from nonebot.typing import T_State
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot_plugin_alconna import At
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.message import run_preprocessor
|
||||
from nonebot.exception import IgnoredException
|
||||
from nonebot_plugin_session import EventSession
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.configs.config import Config
|
||||
from zhenxun.utils.enum import PluginType
|
||||
from zhenxun.utils.utils import FreqLimiter
|
||||
from zhenxun.utils.message import MessageUtils
|
||||
from zhenxun.models.ban_console import BanConsole
|
||||
from zhenxun.models.group_console import GroupConsole
|
||||
from zhenxun.utils.enum import PluginType
|
||||
from zhenxun.utils.message import MessageUtils
|
||||
from zhenxun.utils.utils import FreqLimiter
|
||||
|
||||
Config.add_plugin_config(
|
||||
"hook",
|
||||
@@ -41,11 +40,11 @@ async def _(
|
||||
if user_id in bot.config.superusers:
|
||||
return
|
||||
if await BanConsole.is_ban(None, group_id):
|
||||
logging.debug("群组处于黑名单中...", "ban_hook")
|
||||
logger.debug("群组处于黑名单中...", "ban_hook")
|
||||
raise IgnoredException("群组处于黑名单中...")
|
||||
if g := await GroupConsole.get_group(group_id):
|
||||
if g.level < 0:
|
||||
logging.debug("群黑名单, 群权限-1...", "ban_hook")
|
||||
logger.debug("群黑名单, 群权限-1...", "ban_hook")
|
||||
raise IgnoredException("群黑名单, 群权限-1..")
|
||||
if user_id:
|
||||
ban_result = Config.get_config("hook", "BAN_RESULT")
|
||||
@@ -58,12 +57,12 @@ async def _(
|
||||
else:
|
||||
time = abs(int(time))
|
||||
if time < 60:
|
||||
time_str = str(time) + " 秒"
|
||||
time_str = f"{time!s} 秒"
|
||||
else:
|
||||
minute = int(time / 60)
|
||||
if minute > 60:
|
||||
hours = int(minute / 60)
|
||||
minute = minute % 60
|
||||
hours = minute // 60
|
||||
minute %= 60
|
||||
time_str = f"{hours} 小时 {minute}分钟"
|
||||
else:
|
||||
time_str = f"{minute} 分钟"
|
||||
@@ -75,5 +74,5 @@ async def _(
|
||||
f"{ban_result}\n在..在 {time_str} 后才会理你喔",
|
||||
]
|
||||
).send()
|
||||
logging.debug("用户处于黑名单中...", "ban_hook")
|
||||
logger.debug("用户处于黑名单中...", "ban_hook")
|
||||
raise IgnoredException("用户处于黑名单中...")
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from nonebot.plugin import PluginMetadata
|
||||
from nonebot_plugin_session import EventSession
|
||||
from playwright.async_api import TimeoutError
|
||||
from nonebot_plugin_alconna import At, Args, Match, Alconna, Arparma, on_alconna
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils.enum import PluginType
|
||||
from zhenxun.utils.depends import UserName
|
||||
from zhenxun.utils.message import MessageUtils
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
from zhenxun.configs.utils import PluginExtraData
|
||||
from zhenxun.models.group_member_info import GroupInfoUser
|
||||
|
||||
@@ -31,26 +30,29 @@ _matcher = on_alconna(Alconna("我的信息", Args["at_user?", At]), priority=5,
|
||||
@_matcher.handle()
|
||||
async def _(
|
||||
bot: Bot,
|
||||
session: EventSession,
|
||||
session: Uninfo,
|
||||
arparma: Arparma,
|
||||
at_user: Match[At],
|
||||
nickname: str = UserName(),
|
||||
):
|
||||
user_id = session.id1
|
||||
if at_user.available:
|
||||
user_id = session.user.id
|
||||
if at_user.available and session.group:
|
||||
user_id = at_user.result.target
|
||||
if user := await GroupInfoUser.get_or_none(
|
||||
user_id=user_id, group_id=session.id2
|
||||
user_id=user_id, group_id=session.group.id
|
||||
):
|
||||
nickname = user.user_name
|
||||
else:
|
||||
nickname = user_id
|
||||
if not user_id:
|
||||
await MessageUtils.build_message("用户id为空...").finish(reply_to=True)
|
||||
try:
|
||||
result = await get_user_info(bot, user_id, session.id2, nickname)
|
||||
result = await get_user_info(
|
||||
session, bot, user_id, session.group.id if session.group else None, nickname
|
||||
)
|
||||
await MessageUtils.build_message(result).send(at_sender=True)
|
||||
logger.info("获取用户信息", arparma.header_result, session=session)
|
||||
except TimeoutError as e:
|
||||
logger.error("获取用户信息超时", arparma.header_result, session=session, e=e)
|
||||
await MessageUtils.build_message("获取用户信息超时...").finish(reply_to=True)
|
||||
except Exception as e:
|
||||
logger.error("获取用户信息失败", arparma.header_result, session=session, e=e)
|
||||
await MessageUtils.build_message("获取用户信息失败...").finish(reply_to=True)
|
||||
|
||||
@@ -4,6 +4,7 @@ from datetime import datetime, timedelta
|
||||
from nonebot.adapters import Bot
|
||||
from tortoise.functions import Count
|
||||
from tortoise.expressions import RawSQL
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from nonebot_plugin_htmlrender import template_to_pic
|
||||
|
||||
from zhenxun.models.sign_user import SignUser
|
||||
@@ -130,11 +131,12 @@ async def get_chat_history(
|
||||
|
||||
|
||||
async def get_user_info(
|
||||
bot: Bot, user_id: str, group_id: str | None, nickname: str
|
||||
session: Uninfo, bot: Bot, user_id: str, group_id: str | None, nickname: str
|
||||
) -> bytes:
|
||||
"""获取用户个人信息
|
||||
|
||||
参数:
|
||||
session: Uninfo
|
||||
bot: Bot
|
||||
user_id: 用户id
|
||||
group_id: 群id
|
||||
@@ -162,7 +164,7 @@ async def get_user_info(
|
||||
data = {
|
||||
"date": now.date(),
|
||||
"weather": weather,
|
||||
"ava_url": ava_url,
|
||||
"ava_url": session.user.avatar,
|
||||
"nickname": nickname,
|
||||
"title": "勇 者",
|
||||
"race": random.choice(RACE),
|
||||
|
||||
@@ -73,7 +73,7 @@ class Manager:
|
||||
|
||||
def add(
|
||||
self,
|
||||
module_path: str,
|
||||
module: str,
|
||||
data: BaseBlock | PluginCdBlock | PluginCountBlock | PluginLimit,
|
||||
):
|
||||
"""添加限制"""
|
||||
@@ -106,20 +106,20 @@ class Manager:
|
||||
max_count=data.max_count,
|
||||
)
|
||||
if isinstance(data, PluginCdBlock):
|
||||
self.cd_data[module_path] = data
|
||||
self.cd_data[module] = data
|
||||
elif isinstance(data, PluginCountBlock):
|
||||
self.count_data[module_path] = data
|
||||
self.count_data[module] = data
|
||||
elif isinstance(data, BaseBlock):
|
||||
self.block_data[module_path] = data
|
||||
self.block_data[module] = data
|
||||
|
||||
def exist(self, module_path: str, type: PluginLimitType):
|
||||
def exist(self, module: str, type: PluginLimitType):
|
||||
"""是否存在"""
|
||||
if type == PluginLimitType.CD:
|
||||
return module_path in self.cd_data
|
||||
return module in self.cd_data
|
||||
elif type == PluginLimitType.BLOCK:
|
||||
return module_path in self.block_data
|
||||
return module in self.block_data
|
||||
elif type == PluginLimitType.COUNT:
|
||||
return module_path in self.count_data
|
||||
return module in self.count_data
|
||||
|
||||
def init(self):
|
||||
if not self.cd_file.exists():
|
||||
@@ -208,6 +208,8 @@ class Manager:
|
||||
temp = _yaml.load(f)
|
||||
if "PluginCdLimit" in temp.keys():
|
||||
for k, v in temp["PluginCdLimit"].items():
|
||||
if "." in k:
|
||||
k = k.split(".")[-1]
|
||||
self.cd_data[k] = PluginCdBlock.parse_obj(v)
|
||||
|
||||
def __load_block_file(self):
|
||||
@@ -217,6 +219,8 @@ class Manager:
|
||||
temp = _yaml.load(f)
|
||||
if "PluginBlockLimit" in temp.keys():
|
||||
for k, v in temp["PluginBlockLimit"].items():
|
||||
if "." in k:
|
||||
k = k.split(".")[-1]
|
||||
self.block_data[k] = BaseBlock.parse_obj(v)
|
||||
|
||||
def __load_count_file(self):
|
||||
@@ -226,6 +230,8 @@ class Manager:
|
||||
temp = _yaml.load(f)
|
||||
if "PluginCountLimit" in temp.keys():
|
||||
for k, v in temp["PluginCountLimit"].items():
|
||||
if "." in k:
|
||||
k = k.split(".")[-1]
|
||||
self.count_data[k] = PluginCountBlock.parse_obj(v)
|
||||
|
||||
def __replace_data(
|
||||
@@ -270,10 +276,10 @@ class Manager:
|
||||
if not db_data:
|
||||
return (
|
||||
PluginLimit(
|
||||
module=k.split(".")[-1],
|
||||
module_path=k,
|
||||
module=k,
|
||||
module_path=module2plugin[k].module_path,
|
||||
limit_type=limit_type,
|
||||
plugin=module2plugin.get(k),
|
||||
plugin=module2plugin[k],
|
||||
cd=getattr(limit, "cd", None),
|
||||
max_count=getattr(limit, "max_count", None),
|
||||
status=limit.status,
|
||||
@@ -329,12 +335,10 @@ class Manager:
|
||||
]
|
||||
if data := self.__get_file_data(limit_type):
|
||||
db_type_limit_modules = [
|
||||
(limit.module_path, limit.id) for limit in db_type_limits
|
||||
(limit.module, limit.id) for limit in db_type_limits
|
||||
]
|
||||
delete_list.extend(
|
||||
id
|
||||
for module_path, id in db_type_limit_modules
|
||||
if module_path not in data.keys()
|
||||
id for module, id in db_type_limit_modules if module not in data.keys()
|
||||
)
|
||||
for k, v in data.items():
|
||||
if not module2plugin.get(k):
|
||||
@@ -343,7 +347,7 @@ class Manager:
|
||||
f"插件模块 {k} 未加载,已过滤当前 {v._type} 限制..."
|
||||
)
|
||||
continue
|
||||
db_data = [limit for limit in db_type_limits if limit.module_path == k]
|
||||
db_data = [limit for limit in db_type_limits if limit.module == k]
|
||||
db_data, is_create = self.__set_data(
|
||||
k, db_data[0] if db_data else None, v, limit_type, module2plugin
|
||||
)
|
||||
@@ -369,8 +373,8 @@ class Manager:
|
||||
+ list(self.block_data.keys())
|
||||
+ list(self.count_data.keys())
|
||||
)
|
||||
plugins = await PluginInfo.get_plugins(module_path__in=modules)
|
||||
module2plugin = {p.module_path: p for p in plugins}
|
||||
plugins = await PluginInfo.get_plugins(module__in=modules)
|
||||
module2plugin = {p.module: p for p in plugins}
|
||||
create_list, update_list, delete_list = self.__set_db_limits(
|
||||
db_limits, module2plugin, PluginLimitType.CD
|
||||
)
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import nonebot
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
|
||||
path = Path(__file__).parent
|
||||
|
||||
for f in os.listdir(path):
|
||||
_p = path / f
|
||||
if _p.is_dir():
|
||||
nonebot.load_plugins(str(_p.resolve()))
|
||||
|
||||
try:
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
|
||||
nonebot.load_plugins(str((path / "qq").resolve()))
|
||||
except ImportError:
|
||||
logger.warning("未安装 onebot-adapter,无法加载QQ平台专用插件...")
|
||||
|
||||
|
||||
try:
|
||||
from nonebot.adapters.qq import Bot # noqa: F401
|
||||
|
||||
nonebot.load_plugins(str((path / "qq_api").resolve()))
|
||||
except ImportError:
|
||||
logger.warning("未安装 qq-adapter,无法加载QQ官平台专用插件...")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from nonebot import on_notice, on_request
|
||||
from nonebot.plugin import PluginMetadata
|
||||
from nonebot.adapters.onebot.v11 import (
|
||||
@@ -11,6 +12,7 @@ from nonebot.adapters.onebot.v12 import (
|
||||
)
|
||||
|
||||
from zhenxun.utils.enum import PluginType
|
||||
from zhenxun.utils.rules import notice_rule
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
from zhenxun.utils.common_utils import CommonUtils
|
||||
from zhenxun.configs.config import Config, BotConfig
|
||||
@@ -82,16 +84,28 @@ base_config = Config.get("invite_manager")
|
||||
limit_cd = base_config.get("welcome_msg_cd")
|
||||
|
||||
|
||||
group_increase_handle = on_notice(priority=1, block=False)
|
||||
group_increase_handle = on_notice(
|
||||
priority=1,
|
||||
block=False,
|
||||
rule=notice_rule([GroupIncreaseNoticeEvent, GroupMemberIncreaseEvent]),
|
||||
)
|
||||
"""群员增加处理"""
|
||||
group_decrease_handle = on_notice(priority=1, block=False)
|
||||
group_decrease_handle = on_notice(
|
||||
priority=1,
|
||||
block=False,
|
||||
rule=notice_rule([GroupMemberDecreaseEvent, GroupMemberIncreaseEvent]),
|
||||
)
|
||||
"""群员减少处理"""
|
||||
add_group = on_request(priority=1, block=False)
|
||||
"""加群同意请求"""
|
||||
|
||||
|
||||
@group_increase_handle.handle()
|
||||
async def _(bot: Bot, event: GroupIncreaseNoticeEvent | GroupMemberIncreaseEvent):
|
||||
async def _(
|
||||
bot: Bot,
|
||||
session: Uninfo,
|
||||
event: GroupIncreaseNoticeEvent | GroupMemberIncreaseEvent,
|
||||
):
|
||||
user_id = str(event.user_id)
|
||||
group_id = str(event.group_id)
|
||||
if user_id == bot.self_id:
|
||||
@@ -99,17 +113,20 @@ async def _(bot: Bot, event: GroupIncreaseNoticeEvent | GroupMemberIncreaseEvent
|
||||
group, _ = await GroupConsole.get_or_create(
|
||||
group_id=group_id, channel_id__isnull=True
|
||||
)
|
||||
if group.group_flag == 0:
|
||||
try:
|
||||
await GroupManager.add_bot(bot, str(event.operator_id), group_id, group)
|
||||
except ForceAddGroupError as e:
|
||||
await PlatformUtils.send_superuser(bot, e.get_info())
|
||||
try:
|
||||
await GroupManager.add_bot(bot, str(event.operator_id), group_id, group)
|
||||
except ForceAddGroupError as e:
|
||||
await PlatformUtils.send_superuser(bot, e.get_info())
|
||||
else:
|
||||
await GroupManager.add_user(bot, user_id, group_id)
|
||||
await GroupManager.add_user(session, bot, user_id, group_id)
|
||||
|
||||
|
||||
@group_decrease_handle.handle()
|
||||
async def _(bot: Bot, event: GroupDecreaseNoticeEvent | GroupMemberDecreaseEvent):
|
||||
async def _(
|
||||
bot: Bot,
|
||||
session: Uninfo,
|
||||
event: GroupDecreaseNoticeEvent | GroupMemberDecreaseEvent,
|
||||
):
|
||||
user_id = str(event.user_id)
|
||||
group_id = str(event.group_id)
|
||||
if event.sub_type == "kick_me":
|
||||
@@ -120,6 +137,6 @@ async def _(bot: Bot, event: GroupDecreaseNoticeEvent | GroupMemberDecreaseEvent
|
||||
bot, user_id, group_id, str(event.operator_id), event.sub_type
|
||||
)
|
||||
if result and not await CommonUtils.task_is_block(
|
||||
"refund_group_remind", group_id
|
||||
session, "refund_group_remind"
|
||||
):
|
||||
await group_decrease_handle.send(result)
|
||||
|
||||
@@ -7,6 +7,7 @@ from datetime import datetime
|
||||
import ujson as json
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot_plugin_alconna import At
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.configs.config import Config
|
||||
@@ -55,7 +56,7 @@ class GroupManager:
|
||||
block_plugin = ""
|
||||
if plugin_list := await PluginInfo.filter(default_status=False).all():
|
||||
for plugin in plugin_list:
|
||||
block_plugin += f"{plugin.module},"
|
||||
block_plugin += f"<{plugin.module},"
|
||||
group_info = await bot.get_group_info(group_id=group_id)
|
||||
await GroupConsole.create(
|
||||
group_id=group_info["group_id"],
|
||||
@@ -83,10 +84,10 @@ class GroupManager:
|
||||
).values_list("user_id", flat=True)
|
||||
# 即刻刷新权限
|
||||
for user_info in member_list:
|
||||
user_id = user_info["user_id"]
|
||||
user_id = str(user_info["user_id"])
|
||||
role = user_info["role"]
|
||||
if user_id in bot.config.superusers:
|
||||
await LevelUser.set_level(user_id, user_info["group_id"], 9)
|
||||
await LevelUser.set_level(user_id, group_id, 9)
|
||||
logger.debug(
|
||||
"添加超级用户权限: 9",
|
||||
"入群检测",
|
||||
@@ -100,8 +101,8 @@ class GroupManager:
|
||||
):
|
||||
await LevelUser.set_level(
|
||||
user_id,
|
||||
user_info["group_id"],
|
||||
admin_default_auth,
|
||||
group_id,
|
||||
admin_default_auth if role == "admin" else admin_default_auth + 1,
|
||||
)
|
||||
logger.debug(
|
||||
f"添加默认群管理员权限: {admin_default_auth}",
|
||||
@@ -202,7 +203,7 @@ class GroupManager:
|
||||
).send()
|
||||
|
||||
@classmethod
|
||||
async def add_user(cls, bot: Bot, user_id: str, group_id: str):
|
||||
async def add_user(cls, session: Uninfo, bot: Bot, user_id: str, group_id: str):
|
||||
"""拉入用户
|
||||
|
||||
参数:
|
||||
@@ -219,7 +220,7 @@ class GroupManager:
|
||||
)
|
||||
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
|
||||
if not await CommonUtils.task_is_block(
|
||||
"group_welcome", group_id
|
||||
session, "group_welcome"
|
||||
) and cls._flmt.check(group_id):
|
||||
await cls.__send_welcome_message(user_id, group_id)
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from nonebot.message import run_preprocessor
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
from zhenxun.models.friend_user import FriendUser
|
||||
from zhenxun.models.group_console import GroupConsole
|
||||
from zhenxun.models.group_member_info import GroupInfoUser
|
||||
|
||||
|
||||
@run_preprocessor
|
||||
async def do_something(session: Uninfo):
|
||||
platform = PlatformUtils.get_platform(session)
|
||||
if session.group:
|
||||
if not await GroupConsole.exists(group_id=session.group.id):
|
||||
await GroupConsole.create(group_id=session.group.id)
|
||||
logger.info("添加当前群组ID信息" "", session=session)
|
||||
|
||||
if not await GroupInfoUser.exists(
|
||||
user_id=session.user.id, group_id=session.group.id
|
||||
):
|
||||
await GroupInfoUser.create(
|
||||
user_id=session.user.id, group_id=session.group.id, platform=platform
|
||||
)
|
||||
logger.info("添加当前用户群组ID信息", "", session=session)
|
||||
elif not await FriendUser.exists(user_id=session.user.id, platform=platform):
|
||||
await FriendUser.create(user_id=session.user.id, platform=platform)
|
||||
logger.info("添加当前好友用户信息", "", session=session)
|
||||
@@ -15,10 +15,11 @@ __plugin_meta__ = PluginMetadata(
|
||||
description="插件商店",
|
||||
usage="""
|
||||
插件商店 : 查看当前的插件商店
|
||||
添加插件 id : 添加插件
|
||||
移除插件 id : 移除插件
|
||||
添加插件 id or module : 添加插件
|
||||
移除插件 id or module : 移除插件
|
||||
搜索插件 name or author : 搜索插件
|
||||
更新插件 id : 更新插件
|
||||
更新插件 id or module : 更新插件
|
||||
更新全部插件 : 更新全部插件
|
||||
""".strip(),
|
||||
extra=PluginExtraData(
|
||||
author="HibiKier",
|
||||
@@ -30,10 +31,11 @@ __plugin_meta__ = PluginMetadata(
|
||||
_matcher = on_alconna(
|
||||
Alconna(
|
||||
"插件商店",
|
||||
Subcommand("add", Args["plugin_id", int]),
|
||||
Subcommand("remove", Args["plugin_id", int]),
|
||||
Subcommand("add", Args["plugin_id", int | str]),
|
||||
Subcommand("remove", Args["plugin_id", int | str]),
|
||||
Subcommand("search", Args["plugin_name_or_author", str]),
|
||||
Subcommand("update", Args["plugin_id", int]),
|
||||
Subcommand("update", Args["plugin_id", int | str]),
|
||||
Subcommand("update_all"),
|
||||
),
|
||||
permission=SUPERUSER,
|
||||
priority=1,
|
||||
@@ -68,6 +70,13 @@ _matcher.shortcut(
|
||||
prefix=True,
|
||||
)
|
||||
|
||||
_matcher.shortcut(
|
||||
r"更新全部插件",
|
||||
command="插件商店",
|
||||
arguments=["update_all"],
|
||||
prefix=True,
|
||||
)
|
||||
|
||||
|
||||
@_matcher.assign("$main")
|
||||
async def _(session: EventSession):
|
||||
@@ -81,9 +90,12 @@ async def _(session: EventSession):
|
||||
|
||||
|
||||
@_matcher.assign("add")
|
||||
async def _(session: EventSession, plugin_id: int):
|
||||
async def _(session: EventSession, plugin_id: int | str):
|
||||
try:
|
||||
await MessageUtils.build_message(f"正在添加插件 Id: {plugin_id}").send()
|
||||
if isinstance(plugin_id, str):
|
||||
await MessageUtils.build_message(f"正在添加插件 Module: {plugin_id}").send()
|
||||
else:
|
||||
await MessageUtils.build_message(f"正在添加插件 Id: {plugin_id}").send()
|
||||
result = await ShopManage.add_plugin(plugin_id)
|
||||
except Exception as e:
|
||||
logger.error(f"添加插件 Id: {plugin_id}失败", "插件商店", session=session, e=e)
|
||||
@@ -95,7 +107,7 @@ async def _(session: EventSession, plugin_id: int):
|
||||
|
||||
|
||||
@_matcher.assign("remove")
|
||||
async def _(session: EventSession, plugin_id: int):
|
||||
async def _(session: EventSession, plugin_id: int | str):
|
||||
try:
|
||||
result = await ShopManage.remove_plugin(plugin_id)
|
||||
except Exception as e:
|
||||
@@ -126,9 +138,12 @@ async def _(session: EventSession, plugin_name_or_author: str):
|
||||
|
||||
|
||||
@_matcher.assign("update")
|
||||
async def _(session: EventSession, plugin_id: int):
|
||||
async def _(session: EventSession, plugin_id: int | str):
|
||||
try:
|
||||
await MessageUtils.build_message(f"正在更新插件 Id: {plugin_id}").send()
|
||||
if isinstance(plugin_id, str):
|
||||
await MessageUtils.build_message(f"正在更新插件 Module: {plugin_id}").send()
|
||||
else:
|
||||
await MessageUtils.build_message(f"正在更新插件 Id: {plugin_id}").send()
|
||||
result = await ShopManage.update_plugin(plugin_id)
|
||||
except Exception as e:
|
||||
logger.error(f"更新插件 Id: {plugin_id}失败", "插件商店", session=session, e=e)
|
||||
@@ -137,3 +152,16 @@ async def _(session: EventSession, plugin_id: int):
|
||||
).finish()
|
||||
logger.info(f"更新插件 Id: {plugin_id}", "插件商店", session=session)
|
||||
await MessageUtils.build_message(result).send()
|
||||
|
||||
@_matcher.assign("update_all")
|
||||
async def _(session: EventSession):
|
||||
try:
|
||||
await MessageUtils.build_message("正在更新全部插件").send()
|
||||
result = await ShopManage.update_all_plugin()
|
||||
except Exception as e:
|
||||
logger.error("更新全部插件失败", "插件商店", session=session, e=e)
|
||||
await MessageUtils.build_message(
|
||||
f"更新全部插件失败 e: {e}"
|
||||
).finish()
|
||||
logger.info("更新全部插件", "插件商店", session=session)
|
||||
await MessageUtils.build_message(result).send()
|
||||
@@ -175,19 +175,20 @@ class ShopManage:
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def add_plugin(cls, plugin_id: int) -> str:
|
||||
async def add_plugin(cls, plugin_id: int | str) -> str:
|
||||
"""添加插件
|
||||
|
||||
参数:
|
||||
plugin_id: 插件id
|
||||
plugin_id: 插件id或模块名
|
||||
|
||||
返回:
|
||||
str: 返回消息
|
||||
"""
|
||||
data: dict[str, StorePluginInfo] = await cls.get_data()
|
||||
if plugin_id < 0 or plugin_id >= len(data):
|
||||
return "插件ID不存在..."
|
||||
plugin_key = list(data.keys())[plugin_id]
|
||||
try:
|
||||
plugin_key = await cls._resolve_plugin_key(plugin_id)
|
||||
except ValueError as e:
|
||||
return str(e)
|
||||
plugin_list = await cls.get_loaded_plugins("module")
|
||||
plugin_info = data[plugin_key]
|
||||
if plugin_info.module in [p[0] for p in plugin_list]:
|
||||
@@ -265,20 +266,21 @@ class ShopManage:
|
||||
raise Exception("插件下载失败")
|
||||
|
||||
@classmethod
|
||||
async def remove_plugin(cls, plugin_id: int) -> str:
|
||||
async def remove_plugin(cls, plugin_id: int | str) -> str:
|
||||
"""移除插件
|
||||
|
||||
参数:
|
||||
plugin_id: 插件id
|
||||
plugin_id: 插件id或模块名
|
||||
|
||||
返回:
|
||||
str: 返回消息
|
||||
"""
|
||||
data: dict[str, StorePluginInfo] = await cls.get_data()
|
||||
if plugin_id < 0 or plugin_id >= len(data):
|
||||
return "插件ID不存在..."
|
||||
plugin_key = list(data.keys())[plugin_id]
|
||||
plugin_info = data[plugin_key] # type: ignore
|
||||
try:
|
||||
plugin_key = await cls._resolve_plugin_key(plugin_id)
|
||||
except ValueError as e:
|
||||
return str(e)
|
||||
plugin_info = data[plugin_key]
|
||||
path = BASE_PATH
|
||||
if plugin_info.github_url:
|
||||
path = BASE_PATH / "plugins"
|
||||
@@ -340,7 +342,7 @@ class ShopManage:
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def update_plugin(cls, plugin_id: int) -> str:
|
||||
async def update_plugin(cls, plugin_id: int | str) -> str:
|
||||
"""更新插件
|
||||
|
||||
参数:
|
||||
@@ -350,9 +352,10 @@ class ShopManage:
|
||||
str: 返回消息
|
||||
"""
|
||||
data: dict[str, StorePluginInfo] = await cls.get_data()
|
||||
if plugin_id < 0 or plugin_id >= len(data):
|
||||
return "插件ID不存在..."
|
||||
plugin_key = list(data.keys())[plugin_id]
|
||||
try:
|
||||
plugin_key = await cls._resolve_plugin_key(plugin_id)
|
||||
except ValueError as e:
|
||||
return str(e)
|
||||
logger.info(f"尝试更新插件 {plugin_key}", "插件管理")
|
||||
plugin_info = data[plugin_key]
|
||||
plugin_list = await cls.get_loaded_plugins("module", "version")
|
||||
@@ -373,3 +376,56 @@ class ShopManage:
|
||||
is_external,
|
||||
)
|
||||
return f"插件 {plugin_key} 更新成功! 重启后生效"
|
||||
|
||||
@classmethod
|
||||
async def update_all_plugin(cls) -> str:
|
||||
"""更新插件
|
||||
|
||||
参数:
|
||||
plugin_id: 插件id
|
||||
|
||||
返回:
|
||||
str: 返回消息
|
||||
"""
|
||||
data: dict[str, StorePluginInfo] = await cls.get_data()
|
||||
plugin_list = list(data.keys())
|
||||
update_list = []
|
||||
logger.info(f"尝试更新全部插件 {plugin_list}", "插件管理")
|
||||
for plugin_key in plugin_list:
|
||||
plugin_info = data[plugin_key]
|
||||
plugin_list = await cls.get_loaded_plugins("module", "version")
|
||||
suc_plugin = {p[0]: (p[1] or "Unknown") for p in plugin_list}
|
||||
if plugin_info.module not in [p[0] for p in plugin_list]:
|
||||
logger.debug(f"插件 {plugin_key} 未安装,跳过", "插件管理")
|
||||
continue
|
||||
if cls.check_version_is_new(plugin_info, suc_plugin):
|
||||
logger.debug(f"插件 {plugin_key} 已是最新版本,跳过", "插件管理")
|
||||
continue
|
||||
logger.info(f"正在更新插件 {plugin_key}", "插件管理")
|
||||
is_external = True
|
||||
if plugin_info.github_url is None:
|
||||
plugin_info.github_url = DEFAULT_GITHUB_URL
|
||||
is_external = False
|
||||
await cls.install_plugin_with_repo(
|
||||
plugin_info.github_url,
|
||||
plugin_info.module_path,
|
||||
plugin_info.is_dir,
|
||||
is_external,
|
||||
)
|
||||
update_list.append(plugin_key)
|
||||
if len(update_list) == 0:
|
||||
return "全部插件已是最新版本"
|
||||
return "已更新插件 {}\n共计{}个插件! 重启后生效".format(
|
||||
"\n- ".join(update_list), len(update_list)
|
||||
)
|
||||
@classmethod
|
||||
async def _resolve_plugin_key(cls, plugin_id: int | str) -> str:
|
||||
data: dict[str, StorePluginInfo] = await cls.get_data()
|
||||
if isinstance(plugin_id, int):
|
||||
if plugin_id < 0 or plugin_id >= len(data):
|
||||
raise ValueError("插件ID不存在...")
|
||||
return list(data.keys())[plugin_id]
|
||||
elif isinstance(plugin_id, str):
|
||||
if plugin_id not in [v.module for k, v in data.items()]:
|
||||
raise ValueError("插件Module不存在...")
|
||||
return {v.module: k for k, v in data.items()}[plugin_id]
|
||||
|
||||
@@ -53,6 +53,7 @@ async def _():
|
||||
_group, _ = await GroupConsole.get_or_create(
|
||||
group_id=group.group_id, channel_id__isnull=True
|
||||
)
|
||||
modules = [f"<{module}" for module in modules]
|
||||
_group.block_task = ",".join(modules) + "," # type: ignore
|
||||
update_list.append(_group)
|
||||
logger.info(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import nonebot
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.plugin import PluginMetadata
|
||||
from nonebot_plugin_apscheduler import scheduler
|
||||
|
||||
@@ -26,8 +27,8 @@ __plugin_meta__ = PluginMetadata(
|
||||
driver = nonebot.get_driver()
|
||||
|
||||
|
||||
async def check(group_id: str) -> bool:
|
||||
return not await CommonUtils.task_is_block("morning_goodnight", group_id)
|
||||
async def check(bot: Bot, group_id: str) -> bool:
|
||||
return not await CommonUtils.task_is_block(bot, "morning_goodnight", group_id)
|
||||
|
||||
|
||||
# 早上好
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
from asyncio.exceptions import TimeoutError
|
||||
|
||||
import nonebot
|
||||
import aiofiles
|
||||
import ujson as json
|
||||
from nonebot.drivers import Driver
|
||||
from nonebot_plugin_apscheduler import scheduler
|
||||
|
||||
from zhenxun.configs.path_config import TEXT_PATH
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils.http_utils import AsyncHttpx
|
||||
from zhenxun.configs.path_config import TEXT_PATH
|
||||
from zhenxun.models.group_console import GroupConsole
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
@@ -19,8 +21,8 @@ async def update_city():
|
||||
这里直接更新,避免插件内代码重复
|
||||
"""
|
||||
china_city = TEXT_PATH / "china_city.json"
|
||||
data = {}
|
||||
if not china_city.exists():
|
||||
data = {}
|
||||
try:
|
||||
logger.debug("开始更新城市列表...")
|
||||
res = await AsyncHttpx.get(
|
||||
@@ -38,7 +40,7 @@ async def update_city():
|
||||
city_data = json.loads(res.text)
|
||||
for city in city_data.keys():
|
||||
data[provinces_data[province]].append(city_data[city])
|
||||
with open(china_city, "w", encoding="utf8") as f:
|
||||
async with aiofiles.open(china_city, "w", encoding="utf8") as f:
|
||||
json.dump(data, f, indent=4, ensure_ascii=False)
|
||||
logger.info("自动更新城市列表完成.....")
|
||||
except TimeoutError as e:
|
||||
@@ -46,7 +48,7 @@ async def update_city():
|
||||
except ValueError as e:
|
||||
logger.warning("自动城市列表失败.....", e=e)
|
||||
except Exception as e:
|
||||
logger.error(f"自动城市列表未知错误", e=e)
|
||||
logger.error("自动城市列表未知错误", e=e)
|
||||
|
||||
|
||||
# 自动更新城市列表
|
||||
@@ -57,3 +59,31 @@ async def update_city():
|
||||
)
|
||||
async def _():
|
||||
await update_city()
|
||||
|
||||
|
||||
@driver.on_startup
|
||||
async def _():
|
||||
"""开启/禁用插件格式修改"""
|
||||
_, is_create = await GroupConsole.get_or_create(group_id=133133133)
|
||||
"""标记"""
|
||||
if is_create:
|
||||
data_list = []
|
||||
for group in await GroupConsole.all():
|
||||
if group.block_plugin:
|
||||
if modules := group.block_plugin.split(","):
|
||||
block_plugin = "".join(
|
||||
(f"{module}," if module.startswith("<") else f"<{module},")
|
||||
for module in modules
|
||||
if module.strip()
|
||||
)
|
||||
group.block_plugin = block_plugin.replace("<,", "")
|
||||
if group.block_task:
|
||||
if modules := group.block_task.split(","):
|
||||
block_task = "".join(
|
||||
(f"{module}," if module.startswith("<") else f"<{module},")
|
||||
for module in modules
|
||||
if module.strip()
|
||||
)
|
||||
group.block_task = block_task.replace("<,", "")
|
||||
data_list.append(group)
|
||||
await GroupConsole.bulk_update(data_list, ["block_plugin", "block_task"], 10)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from nonebot.plugin import PluginMetadata
|
||||
from nonebot_plugin_session import EventSession
|
||||
from nonebot_plugin_userinfo import UserInfo, EventUserInfo
|
||||
from nonebot_plugin_alconna import (
|
||||
Args,
|
||||
Match,
|
||||
Query,
|
||||
Option,
|
||||
UniMsg,
|
||||
@@ -17,6 +18,7 @@ from nonebot_plugin_alconna import (
|
||||
)
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils.depends import UserName
|
||||
from zhenxun.utils.message import MessageUtils
|
||||
from zhenxun.utils.exception import GoodsNotFound
|
||||
from zhenxun.utils.enum import BlockType, PluginType
|
||||
@@ -53,8 +55,8 @@ _matcher = on_alconna(
|
||||
Option("--all", action=store_true),
|
||||
Subcommand("my-cost", help_text="我的金币"),
|
||||
Subcommand("my-props", help_text="我的道具"),
|
||||
Subcommand("buy", Args["name", str]["num", int, 1], help_text="购买道具"),
|
||||
Subcommand("use", Args["name", str]["num?", int, 1], help_text="使用道具"),
|
||||
Subcommand("buy", Args["name?", str]["num?", int], help_text="购买道具"),
|
||||
Subcommand("use", Args["name?", str]["num?", int], help_text="使用道具"),
|
||||
Subcommand("gold-list", Args["num?", int], help_text="金币排行"),
|
||||
),
|
||||
priority=5,
|
||||
@@ -76,16 +78,16 @@ _matcher.shortcut(
|
||||
)
|
||||
|
||||
_matcher.shortcut(
|
||||
"购买道具",
|
||||
"购买道具(?P<name>.*?)",
|
||||
command="商店",
|
||||
arguments=["buy", "{%0}"],
|
||||
arguments=["buy", "{name}"],
|
||||
prefix=True,
|
||||
)
|
||||
|
||||
_matcher.shortcut(
|
||||
"使用道具",
|
||||
"使用道具(?P<name>.*?)",
|
||||
command="商店",
|
||||
arguments=["use", "{%0}"],
|
||||
arguments=["use", "{name}"],
|
||||
prefix=True,
|
||||
)
|
||||
|
||||
@@ -122,14 +124,12 @@ async def _(session: EventSession, arparma: Arparma):
|
||||
|
||||
|
||||
@_matcher.assign("my-props")
|
||||
async def _(
|
||||
session: EventSession, arparma: Arparma, user_info: UserInfo = EventUserInfo()
|
||||
):
|
||||
async def _(session: EventSession, arparma: Arparma, nickname: str = UserName()):
|
||||
if session.id1:
|
||||
logger.info("查看道具", arparma.header_result, session=session)
|
||||
if image := await ShopManage.my_props(
|
||||
session.id1,
|
||||
user_info.user_displayname or user_info.user_name,
|
||||
nickname,
|
||||
session.platform,
|
||||
):
|
||||
await MessageUtils.build_message(image.pic2bytes()).finish(reply_to=True)
|
||||
@@ -139,17 +139,23 @@ async def _(
|
||||
|
||||
|
||||
@_matcher.assign("buy")
|
||||
async def _(session: EventSession, arparma: Arparma, name: str, num: int):
|
||||
if session.id1:
|
||||
logger.info(
|
||||
f"购买道具 {name}, 数量: {num}",
|
||||
arparma.header_result,
|
||||
session=session,
|
||||
)
|
||||
result = await ShopManage.buy_prop(session.id1, name, num, session.platform)
|
||||
await MessageUtils.build_message(result).send(reply_to=True)
|
||||
else:
|
||||
await MessageUtils.build_message("用户id为空...").send(reply_to=True)
|
||||
async def _(
|
||||
session: Uninfo,
|
||||
arparma: Arparma,
|
||||
name: Match[str],
|
||||
num: Query[int] = AlconnaQuery("num", 1),
|
||||
):
|
||||
if not name.available:
|
||||
await MessageUtils.build_message(
|
||||
"请在指令后跟需要购买的道具名称或id..."
|
||||
).finish(reply_to=True)
|
||||
logger.info(
|
||||
f"购买道具 {name}, 数量: {num}",
|
||||
arparma.header_result,
|
||||
session=session,
|
||||
)
|
||||
result = await ShopManage.buy_prop(session.user.id, name.result, num.result)
|
||||
await MessageUtils.build_message(result).send(reply_to=True)
|
||||
|
||||
|
||||
@_matcher.assign("use")
|
||||
@@ -159,11 +165,17 @@ async def _(
|
||||
message: UniMsg,
|
||||
session: EventSession,
|
||||
arparma: Arparma,
|
||||
name: str,
|
||||
num: int,
|
||||
name: Match[str],
|
||||
num: Query[int] = AlconnaQuery("num", 1),
|
||||
):
|
||||
if not name.available:
|
||||
await MessageUtils.build_message(
|
||||
"请在指令后跟需要使用的道具名称或id..."
|
||||
).finish(reply_to=True)
|
||||
try:
|
||||
result = await ShopManage.use(bot, event, session, message, name, num, "")
|
||||
result = await ShopManage.use(
|
||||
bot, event, session, message, name.result, num.result, ""
|
||||
)
|
||||
logger.info(
|
||||
f"使用道具 {name}, 数量: {num}", arparma.header_result, session=session
|
||||
)
|
||||
@@ -179,24 +191,21 @@ async def _(
|
||||
|
||||
@_matcher.assign("gold-list")
|
||||
async def _(
|
||||
session: EventSession, arparma: Arparma, num: Query[int] = AlconnaQuery("num", 10)
|
||||
session: Uninfo, arparma: Arparma, num: Query[int] = AlconnaQuery("num", 10)
|
||||
):
|
||||
if num.result > 50:
|
||||
await MessageUtils.build_message("排行榜人数不能超过50哦...").finish()
|
||||
if session.id1:
|
||||
gid = session.id3 or session.id2
|
||||
if not arparma.find("all") and not gid:
|
||||
await MessageUtils.build_message(
|
||||
"私聊中无法查看 '金币排行',请发送 '金币总排行'"
|
||||
).finish()
|
||||
if arparma.find("all"):
|
||||
gid = None
|
||||
result = await gold_rank(session.id1, gid, num.result, session.platform)
|
||||
logger.info(
|
||||
"查看金币排行",
|
||||
arparma.header_result,
|
||||
session=session,
|
||||
)
|
||||
await MessageUtils.build_message(result).send(reply_to=True)
|
||||
else:
|
||||
await MessageUtils.build_message("用户id为空...").send(reply_to=True)
|
||||
gid = session.group.id if session.group else None
|
||||
if not arparma.find("all") and not gid:
|
||||
await MessageUtils.build_message(
|
||||
"私聊中无法查看 '金币排行',请发送 '金币总排行'"
|
||||
).finish()
|
||||
if arparma.find("all"):
|
||||
gid = None
|
||||
result = await gold_rank(session, gid, num.result)
|
||||
logger.info(
|
||||
"查看金币排行",
|
||||
arparma.header_result,
|
||||
session=session,
|
||||
)
|
||||
await MessageUtils.build_message(result).send(reply_to=True)
|
||||
|
||||
@@ -6,6 +6,7 @@ from types import MappingProxyType
|
||||
from collections.abc import Callable
|
||||
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from pydantic import BaseModel, create_model
|
||||
from nonebot_plugin_session import EventSession
|
||||
from nonebot_plugin_alconna import UniMsg, UniMessage
|
||||
@@ -58,9 +59,9 @@ class Goods(BaseModel):
|
||||
class ShopParam(BaseModel):
|
||||
goods_name: str
|
||||
"""商品名称"""
|
||||
user_id: int
|
||||
user_id: str
|
||||
"""用户id"""
|
||||
group_id: int
|
||||
group_id: str | None
|
||||
"""群聊id"""
|
||||
bot: Any
|
||||
"""bot"""
|
||||
@@ -80,16 +81,21 @@ class ShopParam(BaseModel):
|
||||
"""UniMessage"""
|
||||
|
||||
|
||||
async def gold_rank(user_id: str, group_id: str | None, num: int, platform: str):
|
||||
async def gold_rank(
|
||||
session: Uninfo, group_id: str | None, num: int
|
||||
) -> BuildImage | str:
|
||||
query = UserConsole
|
||||
if group_id:
|
||||
uid_list = await GroupInfoUser.filter(group_id=group_id).values_list(
|
||||
"user_id", flat=True
|
||||
)
|
||||
query = query.filter(user_id__in=uid_list)
|
||||
if uid_list:
|
||||
query = query.filter(user_id__in=uid_list)
|
||||
user_list = await query.annotate().order_by("-gold").values_list("user_id", "gold")
|
||||
if not user_list:
|
||||
return "当前还没有人拥有金币哦..."
|
||||
user_id_list = [user[0] for user in user_list]
|
||||
index = user_id_list.index(user_id) + 1
|
||||
index = user_id_list.index(session.user.id) + 1
|
||||
user_list = user_list[:num] if num < len(user_list) else user_list
|
||||
friend_user = await FriendUser.filter(user_id__in=user_id_list).values_list(
|
||||
"user_id", "user_name"
|
||||
@@ -103,8 +109,11 @@ async def gold_rank(user_id: str, group_id: str | None, num: int, platform: str)
|
||||
uid2name[g[0]] = g[1]
|
||||
column_name = ["排名", "-", "名称", "金币", "平台"]
|
||||
data_list = []
|
||||
platform = PlatformUtils.get_platform(session)
|
||||
for i, user in enumerate(user_list):
|
||||
ava_bytes = await PlatformUtils.get_user_avatar(user[0], platform)
|
||||
ava_bytes = await PlatformUtils.get_user_avatar(
|
||||
user[0], platform, session.self_id
|
||||
)
|
||||
data_list.append(
|
||||
[
|
||||
f"{i+1}",
|
||||
@@ -294,9 +303,12 @@ class ShopManage:
|
||||
str | MessageFactory | None: 使用完成后返回信息
|
||||
"""
|
||||
if goods_name.isdigit():
|
||||
user = await UserConsole.get_user(user_id=session.id1) # type: ignore
|
||||
uuid = list(user.props.keys())[int(goods_name)]
|
||||
goods_info = await GoodsInfo.get_or_none(uuid=uuid)
|
||||
try:
|
||||
user = await UserConsole.get_user(user_id=session.id1) # type: ignore
|
||||
uuid = list(user.props.keys())[int(goods_name)]
|
||||
goods_info = await GoodsInfo.get_or_none(uuid=uuid)
|
||||
except IndexError:
|
||||
return "仓库中道具不存在..."
|
||||
else:
|
||||
goods_info = await GoodsInfo.get_or_none(goods_name=goods_name)
|
||||
if not goods_info:
|
||||
@@ -647,9 +659,10 @@ class ShopManage:
|
||||
shop = BuildImage(w, h, font_size=20, color="#f9f6f2")
|
||||
await shop.paste(A, (20, 230))
|
||||
await shop.paste(shop_logo, (450, 30))
|
||||
tip = "注【通过 购买道具 序号 或者 商品名称 购买】"
|
||||
await shop.text(
|
||||
(
|
||||
int((1000 - shop.getsize("注【通过 序号 或者 商品名称 购买】")[0]) / 2),
|
||||
int((1000 - shop.getsize(tip)[0]) / 2),
|
||||
170,
|
||||
),
|
||||
"注【通过 序号 或者 商品名称 购买】",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from nonebot.plugin import PluginMetadata
|
||||
from nonebot_plugin_session import EventSession
|
||||
from nonebot_plugin_apscheduler import scheduler
|
||||
@@ -115,6 +116,13 @@ _sign_matcher.shortcut(
|
||||
prefix=True,
|
||||
)
|
||||
|
||||
_sign_matcher.shortcut(
|
||||
"签到排行",
|
||||
command="签到",
|
||||
arguments=["--list"],
|
||||
prefix=True,
|
||||
)
|
||||
|
||||
_sign_matcher.shortcut(
|
||||
"好感度总排行",
|
||||
command="签到",
|
||||
@@ -122,43 +130,44 @@ _sign_matcher.shortcut(
|
||||
prefix=True,
|
||||
)
|
||||
|
||||
_sign_matcher.shortcut(
|
||||
"签到总排行",
|
||||
command="签到",
|
||||
arguments=["--global", "--list"],
|
||||
prefix=True,
|
||||
)
|
||||
|
||||
|
||||
@_sign_matcher.assign("$main")
|
||||
async def _(session: EventSession, arparma: Arparma, nickname: str = UserName()):
|
||||
if session.id1:
|
||||
if path := await SignManage.sign(session, nickname):
|
||||
logger.info("签到成功", arparma.header_result, session=session)
|
||||
await MessageUtils.build_message(path).finish()
|
||||
return MessageUtils.build_message("用户id为空...").send()
|
||||
async def _(session: Uninfo, arparma: Arparma, nickname: str = UserName()):
|
||||
path = await SignManage.sign(session, nickname)
|
||||
logger.info("签到成功", arparma.header_result, session=session)
|
||||
await MessageUtils.build_message(path).finish()
|
||||
|
||||
|
||||
@_sign_matcher.assign("my")
|
||||
async def _(session: EventSession, arparma: Arparma, nickname: str = UserName()):
|
||||
if session.id1:
|
||||
if image := await SignManage.sign(session, nickname, True):
|
||||
logger.info("查看我的签到", arparma.header_result, session=session)
|
||||
await MessageUtils.build_message(image).finish()
|
||||
return MessageUtils.build_message("用户id为空...").send()
|
||||
async def _(session: Uninfo, arparma: Arparma, nickname: str = UserName()):
|
||||
path = await SignManage.sign(session, nickname, True)
|
||||
logger.info("查看我的签到", arparma.header_result, session=session)
|
||||
await MessageUtils.build_message(path).finish()
|
||||
|
||||
|
||||
@_sign_matcher.assign("list")
|
||||
async def _(
|
||||
session: EventSession, arparma: Arparma, num: Query[int] = AlconnaQuery("num", 10)
|
||||
session: Uninfo, arparma: Arparma, num: Query[int] = AlconnaQuery("num", 10)
|
||||
):
|
||||
if num.result > 50:
|
||||
await MessageUtils.build_message("排行榜人数不能超过50哦...").finish()
|
||||
gid = session.id3 or session.id2
|
||||
gid = session.group.id if session.group else None
|
||||
if not arparma.find("global") and not gid:
|
||||
await MessageUtils.build_message(
|
||||
"私聊中无法查看 '好感度排行',请发送 '好感度总排行'"
|
||||
).finish()
|
||||
if session.id1:
|
||||
if arparma.find("global"):
|
||||
gid = None
|
||||
if image := await SignManage.rank(session.id1, num.result, gid):
|
||||
logger.info("查看签到排行", arparma.header_result, session=session)
|
||||
await MessageUtils.build_message(image).finish()
|
||||
return MessageUtils.build_message("用户id为空...").send()
|
||||
if arparma.find("global"):
|
||||
gid = None
|
||||
image = await SignManage.rank(session, num.result, gid)
|
||||
logger.info("查看签到排行", arparma.header_result, session=session)
|
||||
await MessageUtils.build_message(image).send()
|
||||
|
||||
|
||||
@scheduler.scheduled_job(
|
||||
|
||||
@@ -4,12 +4,12 @@ from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
import pytz
|
||||
from nonebot_plugin_session import EventSession
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.models.sign_log import SignLog
|
||||
from zhenxun.models.sign_user import SignUser
|
||||
from zhenxun.utils.utils import get_user_avatar
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
from zhenxun.models.friend_user import FriendUser
|
||||
from zhenxun.configs.path_config import IMAGE_PATH
|
||||
from zhenxun.models.user_console import UserConsole
|
||||
@@ -32,12 +32,12 @@ PLATFORM_PATH = {
|
||||
class SignManage:
|
||||
@classmethod
|
||||
async def rank(
|
||||
cls, user_id: str, num: int, group_id: str | None = None
|
||||
) -> BuildImage: # sourcery skip: avoid-builtin-shadow
|
||||
cls, session: Uninfo, num: int, group_id: str | None = None
|
||||
) -> BuildImage | str: # sourcery skip: avoid-builtin-shadow
|
||||
"""好感度排行
|
||||
|
||||
参数:
|
||||
user_id: 用户id
|
||||
session: Uninfo
|
||||
num: 排行榜数量
|
||||
group_id: 群组id
|
||||
|
||||
@@ -49,14 +49,17 @@ class SignManage:
|
||||
user_list = await GroupInfoUser.filter(group_id=group_id).values_list(
|
||||
"user_id", flat=True
|
||||
)
|
||||
query = query.filter(user_id__in=user_list)
|
||||
if user_list:
|
||||
query = query.filter(user_id__in=user_list)
|
||||
user_list = (
|
||||
await query.annotate()
|
||||
.order_by("-impression")
|
||||
.values_list("user_id", "impression", "sign_count", "platform")
|
||||
)
|
||||
if not user_list:
|
||||
return "当前还没有人签到过哦..."
|
||||
user_id_list = [user[0] for user in user_list]
|
||||
index = user_id_list.index(user_id) + 1
|
||||
index = user_id_list.index(session.user.id) + 1
|
||||
user_list = user_list[:num] if num < len(user_list) else user_list
|
||||
column_name = ["排名", "-", "名称", "好感度", "签到次数", "平台"]
|
||||
friend_list = await FriendUser.filter(user_id__in=user_id_list).values_list(
|
||||
@@ -70,8 +73,11 @@ class SignManage:
|
||||
for g in group_user:
|
||||
uid2name[g[0]] = g[1]
|
||||
data_list = []
|
||||
platform = PlatformUtils.get_platform(session)
|
||||
for i, user in enumerate(user_list):
|
||||
bytes = await get_user_avatar(user[0])
|
||||
bytes = await PlatformUtils.get_user_avatar(
|
||||
user[0], platform, session.self_id
|
||||
)
|
||||
data_list.append(
|
||||
[
|
||||
f"{i+1}",
|
||||
@@ -92,28 +98,29 @@ class SignManage:
|
||||
|
||||
@classmethod
|
||||
async def sign(
|
||||
cls, session: EventSession, nickname: str, is_card_view: bool = False
|
||||
) -> Path | None:
|
||||
cls, session: Uninfo, nickname: str, is_card_view: bool = False
|
||||
) -> Path:
|
||||
"""签到
|
||||
|
||||
参数:
|
||||
session: Session
|
||||
session: Uninfo
|
||||
nickname: 用户昵称
|
||||
is_card_view: 是否展示卡片
|
||||
|
||||
返回:
|
||||
Path: 卡片路径
|
||||
"""
|
||||
if not session.id1:
|
||||
return None
|
||||
platform = PlatformUtils.get_platform(session)
|
||||
now = datetime.now(pytz.timezone("Asia/Shanghai"))
|
||||
user_console = await UserConsole.get_user(session.id1, session.platform)
|
||||
user_console = await UserConsole.get_user(session.user.id, platform)
|
||||
user, _ = await SignUser.get_or_create(
|
||||
user_id=session.id1,
|
||||
defaults={"user_console": user_console, "platform": session.platform},
|
||||
user_id=session.user.id,
|
||||
defaults={"user_console": user_console, "platform": platform},
|
||||
)
|
||||
new_log = (
|
||||
await SignLog.filter(user_id=session.id1).order_by("-create_time").first()
|
||||
await SignLog.filter(user_id=session.user.id)
|
||||
.order_by("-create_time")
|
||||
.first()
|
||||
)
|
||||
log_time = None
|
||||
if new_log:
|
||||
@@ -123,7 +130,13 @@ class SignManage:
|
||||
if not is_card_view and (not new_log or (log_time and log_time != now.date())):
|
||||
return await cls._handle_sign_in(user, nickname, session)
|
||||
return await get_card(
|
||||
user, nickname, -1, user_console.gold, "", is_card_view=is_card_view
|
||||
user,
|
||||
session,
|
||||
nickname,
|
||||
-1,
|
||||
user_console.gold,
|
||||
"",
|
||||
is_card_view=is_card_view,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@@ -131,36 +144,35 @@ class SignManage:
|
||||
cls,
|
||||
user: SignUser,
|
||||
nickname: str,
|
||||
session: EventSession,
|
||||
session: Uninfo,
|
||||
) -> Path:
|
||||
"""签到处理
|
||||
|
||||
参数:
|
||||
user: SignUser
|
||||
nickname: 用户昵称
|
||||
session: Session
|
||||
session: Uninfo
|
||||
|
||||
返回:
|
||||
Path: 卡片路径
|
||||
"""
|
||||
platform = PlatformUtils.get_platform(session)
|
||||
impression_added = (secrets.randbelow(99) + 1) / 100
|
||||
rand = random.random()
|
||||
add_probability = float(user.add_probability)
|
||||
specify_probability = user.specify_probability
|
||||
if rand + add_probability > 0.97 or rand < specify_probability:
|
||||
impression_added *= 2
|
||||
await SignUser.sign(user, impression_added, session.bot_id, session.platform)
|
||||
await SignUser.sign(user, impression_added, session.self_id, platform)
|
||||
gold = random.randint(1, 100)
|
||||
gift = random_event(float(user.impression))
|
||||
if isinstance(gift, int):
|
||||
gold += gift
|
||||
await UserConsole.add_gold(
|
||||
user.user_id, gold + gift, "sign_in", session.platform
|
||||
)
|
||||
await UserConsole.add_gold(user.user_id, gold + gift, "sign_in", platform)
|
||||
gift = f"额外金币 +{gift}"
|
||||
else:
|
||||
await UserConsole.add_gold(user.user_id, gold, "sign_in", session.platform)
|
||||
await UserConsole.add_props_by_name(user.user_id, gift, 1, session.platform)
|
||||
await UserConsole.add_gold(user.user_id, gold, "sign_in", platform)
|
||||
await UserConsole.add_props_by_name(user.user_id, gift, 1, platform)
|
||||
gift += " + 1"
|
||||
logger.info(
|
||||
f"签到成功. score: {user.impression:.2f} "
|
||||
@@ -170,6 +182,7 @@ class SignManage:
|
||||
)
|
||||
return await get_card(
|
||||
user,
|
||||
session,
|
||||
nickname,
|
||||
impression_added,
|
||||
gold,
|
||||
|
||||
@@ -7,13 +7,13 @@ from datetime import datetime
|
||||
import pytz
|
||||
import nonebot
|
||||
from nonebot.drivers import Driver
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from nonebot_plugin_htmlrender import template_to_pic
|
||||
|
||||
from zhenxun.models.sign_log import SignLog
|
||||
from zhenxun.models.sign_user import SignUser
|
||||
from zhenxun.utils.utils import get_user_avatar
|
||||
from zhenxun.utils.http_utils import AsyncHttpx
|
||||
from zhenxun.utils.image_utils import BuildImage
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
from zhenxun.configs.config import Config, BotConfig
|
||||
from zhenxun.configs.path_config import IMAGE_PATH, TEMPLATE_PATH
|
||||
|
||||
@@ -63,6 +63,7 @@ async def init_image():
|
||||
|
||||
async def get_card(
|
||||
user: SignUser,
|
||||
session: Uninfo,
|
||||
nickname: str,
|
||||
add_impression: float,
|
||||
gold: int | None,
|
||||
@@ -74,6 +75,7 @@ async def get_card(
|
||||
|
||||
参数:
|
||||
user: SignUser
|
||||
session: Uninfo
|
||||
nickname: 用户昵称
|
||||
impression: 新增的好感度
|
||||
gold: 金币
|
||||
@@ -99,17 +101,18 @@ async def get_card(
|
||||
is_card_view = True
|
||||
return (
|
||||
await _generate_html_card(
|
||||
user, nickname, add_impression, gold, gift, is_double, is_card_view
|
||||
user, session, nickname, add_impression, gold, gift, is_double, is_card_view
|
||||
)
|
||||
if base_config.get("IMAGE_STYLE") == "zhenxun"
|
||||
else await _generate_card(
|
||||
user, nickname, add_impression, gold, gift, is_double, is_card_view
|
||||
user, session, nickname, add_impression, gold, gift, is_double, is_card_view
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def _generate_card(
|
||||
user: SignUser,
|
||||
session: Uninfo,
|
||||
nickname: str,
|
||||
add_impression: float,
|
||||
gold: int | None,
|
||||
@@ -121,6 +124,7 @@ async def _generate_card(
|
||||
|
||||
参数:
|
||||
user: SignUser
|
||||
session: Uninfo
|
||||
nickname: 用户昵称
|
||||
add_impression: 新增的好感度
|
||||
gold: 金币
|
||||
@@ -137,7 +141,9 @@ async def _generate_card(
|
||||
140,
|
||||
background=SIGN_BORDER_PATH / "ava_border_01.png",
|
||||
)
|
||||
if user.platform == "qq" and (byt := await get_user_avatar(user.user_id)):
|
||||
if session.user.avatar and (
|
||||
byt := await AsyncHttpx.get_content(session.user.avatar)
|
||||
):
|
||||
ava = BuildImage(107, 107, background=BytesIO(byt))
|
||||
else:
|
||||
ava = BuildImage(107, 107, (0, 0, 0))
|
||||
@@ -273,10 +279,6 @@ async def _generate_card(
|
||||
await bk.paste(nickname_img, (30, 15))
|
||||
await bk.paste(uid_img, (30, 85))
|
||||
await bk.paste(A, (0, 150))
|
||||
# await bk.text((30, 167), "Accumulative check-in for")
|
||||
# _x = bk.getsize("Accumulative check-in for")[0] + sign_day_img.width + 45
|
||||
# await bk.paste(sign_day_img, (398, 158))
|
||||
# await bk.text((_x, 167), "days")
|
||||
await bk.paste(tip_image, (10, 167))
|
||||
await bk.paste(date_img, (220, 370))
|
||||
await bk.paste(lik_text1_img, (220, 240))
|
||||
@@ -377,6 +379,7 @@ def clear_sign_data_pic():
|
||||
|
||||
async def _generate_html_card(
|
||||
user: SignUser,
|
||||
session: Uninfo,
|
||||
nickname: str,
|
||||
add_impression: float,
|
||||
gold: int | None,
|
||||
@@ -388,6 +391,7 @@ async def _generate_html_card(
|
||||
|
||||
参数:
|
||||
user: SignUser
|
||||
session: Uninfo
|
||||
nickname: 用户昵称
|
||||
add_impression: 新增的好感度
|
||||
gold: 金币
|
||||
@@ -420,9 +424,8 @@ async def _generate_html_card(
|
||||
next_impression - previous_impression
|
||||
)
|
||||
now = datetime.now()
|
||||
ava_url = PlatformUtils.get_user_avatar_url(user.user_id, "qq")
|
||||
data = {
|
||||
"ava_url": ava_url,
|
||||
"ava_url": session.user.avatar,
|
||||
"name": nickname,
|
||||
"uid": uid,
|
||||
"sign_count": f"{user.sign_count}",
|
||||
|
||||
@@ -2,18 +2,17 @@ from datetime import datetime, timedelta
|
||||
|
||||
from tortoise.functions import Count
|
||||
|
||||
from zhenxun.models.group_console import GroupConsole
|
||||
from zhenxun.models.group_member_info import GroupInfoUser
|
||||
from zhenxun.models.plugin_info import PluginInfo
|
||||
from zhenxun.utils.enum import PluginType
|
||||
from zhenxun.models.statistics import Statistics
|
||||
from zhenxun.utils.image_utils import BuildImage
|
||||
from zhenxun.models.plugin_info import PluginInfo
|
||||
from zhenxun.utils.echart_utils import ChartUtils
|
||||
from zhenxun.utils.echart_utils.models import Barh
|
||||
from zhenxun.utils.enum import PluginType
|
||||
from zhenxun.utils.image_utils import BuildImage, BuildMat, MatType
|
||||
from zhenxun.models.group_console import GroupConsole
|
||||
from zhenxun.models.group_member_info import GroupInfoUser
|
||||
|
||||
|
||||
class StatisticsManage:
|
||||
|
||||
@classmethod
|
||||
async def get_statistics(
|
||||
cls,
|
||||
@@ -28,12 +27,12 @@ class StatisticsManage:
|
||||
if search_type == "day":
|
||||
day = 1
|
||||
day_type = "日"
|
||||
if search_type == "week":
|
||||
day = 7
|
||||
day_type = "周"
|
||||
if search_type == "month":
|
||||
elif search_type == "month":
|
||||
day = 30
|
||||
day_type = "月"
|
||||
elif search_type == "week":
|
||||
day = 7
|
||||
day_type = "周"
|
||||
if day_type:
|
||||
day_type += f"({day}天)"
|
||||
title = ""
|
||||
@@ -53,7 +52,7 @@ class StatisticsManage:
|
||||
else:
|
||||
title = "功能调用统计"
|
||||
if is_global and not user_id:
|
||||
title = "全局 " + title
|
||||
title = f"全局 {title}"
|
||||
return await cls.get_global_statistics(plugin_name, day, title)
|
||||
if user_id:
|
||||
return await cls.get_my_statistics(user_id, group_id, day, title)
|
||||
@@ -76,9 +75,11 @@ class StatisticsManage:
|
||||
.group_by("plugin_name")
|
||||
.values_list("plugin_name", "count")
|
||||
)
|
||||
if not data_list:
|
||||
return "统计数据为空..."
|
||||
return await cls.__build_image(data_list, title)
|
||||
return (
|
||||
await cls.__build_image(data_list, title)
|
||||
if data_list
|
||||
else "统计数据为空..."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_my_statistics(
|
||||
@@ -95,9 +96,11 @@ class StatisticsManage:
|
||||
.group_by("plugin_name")
|
||||
.values_list("plugin_name", "count")
|
||||
)
|
||||
if not data_list:
|
||||
return "统计数据为空..."
|
||||
return await cls.__build_image(data_list, title)
|
||||
return (
|
||||
await cls.__build_image(data_list, title)
|
||||
if data_list
|
||||
else "统计数据为空..."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_group_statistics(cls, group_id: str, day: int | None, title: str):
|
||||
@@ -110,15 +113,18 @@ class StatisticsManage:
|
||||
.group_by("plugin_name")
|
||||
.values_list("plugin_name", "count")
|
||||
)
|
||||
if not data_list:
|
||||
return "统计数据为空..."
|
||||
return await cls.__build_image(data_list, title)
|
||||
return (
|
||||
await cls.__build_image(data_list, title)
|
||||
if data_list
|
||||
else "统计数据为空..."
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def __build_image(cls, data_list: list[tuple[str, int]], title: str):
|
||||
module2count = {x[0]: x[1] for x in data_list}
|
||||
plugin_info = await PluginInfo.filter(
|
||||
module__in=module2count.keys(),
|
||||
load_status=True,
|
||||
plugin_type=PluginType.NORMAL,
|
||||
).all()
|
||||
x_index = []
|
||||
@@ -126,5 +132,5 @@ class StatisticsManage:
|
||||
for plugin in plugin_info:
|
||||
x_index.append(plugin.name)
|
||||
data.append(module2count.get(plugin.module, 0))
|
||||
barh = Barh(data=data, category_data=x_index)
|
||||
barh = Barh(data=data, category_data=x_index, title=title)
|
||||
return await ChartUtils.barh(barh)
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
from datetime import datetime
|
||||
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.adapters.onebot.v11 import PokeNotifyEvent
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.message import run_postprocessor
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.plugin import PluginMetadata
|
||||
from nonebot.message import run_postprocessor
|
||||
from nonebot_plugin_session import EventSession
|
||||
from nonebot_plugin_apscheduler import scheduler
|
||||
from nonebot.adapters.onebot.v11 import PokeNotifyEvent
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.utils.enum import PluginType
|
||||
from zhenxun.models.statistics import Statistics
|
||||
from zhenxun.configs.utils import PluginExtraData
|
||||
from zhenxun.models.plugin_info import PluginInfo
|
||||
from zhenxun.models.statistics import Statistics
|
||||
from zhenxun.utils.enum import PluginType
|
||||
|
||||
__plugin_meta__ = PluginMetadata(
|
||||
name="功能调用统计",
|
||||
@@ -21,6 +23,8 @@ __plugin_meta__ = PluginMetadata(
|
||||
).dict(),
|
||||
)
|
||||
|
||||
TEMP_LIST = []
|
||||
|
||||
|
||||
@run_postprocessor
|
||||
async def _(
|
||||
@@ -33,16 +37,32 @@ async def _(
|
||||
if matcher.type == "notice" and not isinstance(event, PokeNotifyEvent):
|
||||
"""过滤除poke外的notice"""
|
||||
return
|
||||
if session.id1:
|
||||
plugin = await PluginInfo.get_or_none(module=matcher.module_name)
|
||||
if session.id1 and matcher.plugin:
|
||||
plugin = await PluginInfo.get_plugin(module_path=matcher.plugin.module_name)
|
||||
plugin_type = plugin.plugin_type if plugin else None
|
||||
if plugin_type == PluginType.NORMAL and matcher.plugin_name not in [
|
||||
"update_info",
|
||||
"statistics_handle",
|
||||
]:
|
||||
await Statistics.create(
|
||||
user_id=session.id1,
|
||||
group_id=session.id3 or session.id2,
|
||||
plugin_name=matcher.plugin_name,
|
||||
create_time=datetime.now(),
|
||||
if plugin_type == PluginType.NORMAL:
|
||||
logger.debug(f"提交调用记录: {matcher.plugin_name}...", session=session)
|
||||
TEMP_LIST.append(
|
||||
Statistics(
|
||||
user_id=session.id1,
|
||||
group_id=session.id3 or session.id2,
|
||||
plugin_name=matcher.plugin_name,
|
||||
create_time=datetime.now(),
|
||||
bot_id=bot.self_id,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@scheduler.scheduled_job(
|
||||
"interval",
|
||||
minutes=1,
|
||||
)
|
||||
async def _():
|
||||
try:
|
||||
call_list = TEMP_LIST.copy()
|
||||
TEMP_LIST.clear()
|
||||
if call_list:
|
||||
await Statistics.bulk_create(call_list)
|
||||
logger.debug(f"批量添加调用记录 {len(call_list)} 条", "定时任务")
|
||||
except Exception as e:
|
||||
logger.error("定时批量添加调用记录", "定时任务", e=e)
|
||||
|
||||
@@ -16,7 +16,6 @@ from zhenxun.utils.common_utils import CommonUtils
|
||||
|
||||
|
||||
class BroadcastManage:
|
||||
|
||||
@classmethod
|
||||
async def send(
|
||||
cls, bot: Bot, message: UniMsg, session: EventSession
|
||||
@@ -43,8 +42,9 @@ class BroadcastManage:
|
||||
for group in group_list:
|
||||
try:
|
||||
if not await CommonUtils.task_is_block(
|
||||
group.group_id,
|
||||
bot,
|
||||
"broadcast", # group.channel_id
|
||||
group.group_id,
|
||||
):
|
||||
target = PlatformUtils.get_target(
|
||||
bot, None, group.channel_id or group.group_id
|
||||
|
||||
@@ -1,22 +1,201 @@
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import nonebot
|
||||
from nonebot import require
|
||||
from fastapi import APIRouter
|
||||
from nonebot.config import Config
|
||||
from tortoise.functions import Count
|
||||
from tortoise.expressions import RawSQL
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from zhenxun.models.statistics import Statistics
|
||||
from zhenxun.models.chat_history import ChatHistory
|
||||
from zhenxun.models.bot_connect_log import BotConnectLog
|
||||
|
||||
from ....base_model import Result
|
||||
from .data_source import BotManage
|
||||
from ....utils import authentication
|
||||
from ....base_model import Result, QueryModel, BaseResultModel
|
||||
from .model import BotInfo, ChatCallMonthCount, QueryChatCallCount, AllChatAndCallCount
|
||||
|
||||
require("plugin_store")
|
||||
|
||||
router = APIRouter(prefix="/dashboard")
|
||||
|
||||
driver = nonebot.get_driver()
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_bot_list",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[list[BotInfo]],
|
||||
response_class=JSONResponse,
|
||||
deprecated="获取bot列表", # type: ignore
|
||||
)
|
||||
async def _() -> Result:
|
||||
async def _() -> Result[list[BotInfo]]:
|
||||
try:
|
||||
return Result.ok(await BotManage.get_bot_list(), "拿到信息啦!")
|
||||
except Exception as e:
|
||||
return Result.fail(f"发生了一点错误捏 {type(e)}: {e}")
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_chat_and_call_count",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[QueryChatCallCount],
|
||||
response_class=JSONResponse,
|
||||
description="获取聊天/调用记录的全部和今日数量",
|
||||
)
|
||||
async def _(bot_id: str | None = None) -> Result[QueryChatCallCount]:
|
||||
now = datetime.now()
|
||||
query = ChatHistory
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
chat_all_count = await query.annotate().count()
|
||||
chat_day_count = await query.filter(
|
||||
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
query = Statistics
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
call_all_count = await query.annotate().count()
|
||||
call_day_count = await query.filter(
|
||||
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
return Result.ok(
|
||||
QueryChatCallCount(
|
||||
chat_num=chat_all_count,
|
||||
chat_day=chat_day_count,
|
||||
call_num=call_all_count,
|
||||
call_day=call_day_count,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_all_chat_and_call_count",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[AllChatAndCallCount],
|
||||
response_class=JSONResponse,
|
||||
description="获取聊天/调用记录的全部数据次数",
|
||||
)
|
||||
async def _(bot_id: str | None = None) -> Result[AllChatAndCallCount]:
|
||||
now = datetime.now()
|
||||
query = ChatHistory
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
chat_week_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
chat_month_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=30, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
chat_year_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=365, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
query = Statistics
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
call_week_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
call_month_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=30, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
call_year_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=365, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
return Result.ok(
|
||||
AllChatAndCallCount(
|
||||
chat_week=chat_week_count,
|
||||
chat_month=chat_month_count,
|
||||
chat_year=chat_year_count,
|
||||
call_week=call_week_count,
|
||||
call_month=call_month_count,
|
||||
call_year=call_year_count,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_chat_and_call_month",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[ChatCallMonthCount],
|
||||
response_class=JSONResponse,
|
||||
deprecated="获取聊天/调用记录的一个月数量", # type: ignore
|
||||
)
|
||||
async def _(bot_id: str | None = None) -> Result[ChatCallMonthCount]:
|
||||
now = datetime.now()
|
||||
filter_date = now - timedelta(days=30, hours=now.hour, minutes=now.minute)
|
||||
chat_query = ChatHistory
|
||||
call_query = Statistics
|
||||
if bot_id:
|
||||
chat_query = chat_query.filter(bot_id=bot_id)
|
||||
call_query = call_query.filter(bot_id=bot_id)
|
||||
chat_date_list = (
|
||||
await chat_query.filter(create_time__gte=filter_date)
|
||||
.annotate(date=RawSQL("DATE(create_time)"), count=Count("id"))
|
||||
.group_by("date")
|
||||
.values("date", "count")
|
||||
)
|
||||
call_date_list = (
|
||||
await call_query.filter(create_time__gte=filter_date)
|
||||
.annotate(date=RawSQL("DATE(create_time)"), count=Count("id"))
|
||||
.group_by("date")
|
||||
.values("date", "count")
|
||||
)
|
||||
date_list = []
|
||||
chat_count_list = []
|
||||
call_count_list = []
|
||||
chat_date2cnt = {str(date["date"]): date["count"] for date in chat_date_list}
|
||||
call_date2cnt = {str(date["date"]): date["count"] for date in call_date_list}
|
||||
date = now.date()
|
||||
for _ in range(30):
|
||||
if str(date) in chat_date2cnt:
|
||||
chat_count_list.append(chat_date2cnt[str(date)])
|
||||
else:
|
||||
chat_count_list.append(0)
|
||||
if str(date) in call_date2cnt:
|
||||
call_count_list.append(call_date2cnt[str(date)])
|
||||
else:
|
||||
call_count_list.append(0)
|
||||
date_list.append(str(date)[5:])
|
||||
date -= timedelta(days=1)
|
||||
chat_count_list.reverse()
|
||||
call_count_list.reverse()
|
||||
date_list.reverse()
|
||||
return Result.ok(
|
||||
ChatCallMonthCount(chat=chat_count_list, call=call_count_list, date=date_list)
|
||||
)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/get_connect_log",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[BaseResultModel],
|
||||
response_class=JSONResponse,
|
||||
deprecated="获取Bot连接记录", # type: ignore
|
||||
)
|
||||
async def _(query: QueryModel) -> Result[BaseResultModel]:
|
||||
total = await BotConnectLog.all().count()
|
||||
if total % query.size:
|
||||
total += 1
|
||||
data = (
|
||||
await BotConnectLog.all()
|
||||
.order_by("-id")
|
||||
.offset((query.index - 1) * query.size)
|
||||
.limit(query.size)
|
||||
)
|
||||
for v in data:
|
||||
v.connect_time = v.connect_time.replace(tzinfo=None).replace(microsecond=0)
|
||||
return Result.ok(BaseResultModel(total=total, data=data))
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_nonebot_config",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[Config],
|
||||
response_class=JSONResponse,
|
||||
deprecated="获取nb配置", # type: ignore
|
||||
)
|
||||
async def _() -> Result[Config]:
|
||||
return Result.ok(driver.config)
|
||||
|
||||
@@ -49,11 +49,12 @@ class BotManage:
|
||||
)
|
||||
group_list, _ = await PlatformUtils.get_group_list(bot)
|
||||
group_list = [g for g in group_list if g.channel_id is None]
|
||||
friend_list = await PlatformUtils.get_friend_list(bot)
|
||||
friend_list, _ = await PlatformUtils.get_friend_list(bot)
|
||||
bot_info.group_count = len(group_list)
|
||||
bot_info.friend_count = len(friend_list)
|
||||
bot_info.day_call = await Statistics.filter(
|
||||
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
|
||||
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute),
|
||||
bot_id=bot.self_id,
|
||||
).count()
|
||||
bot_info.received_messages = await ChatHistory.filter(
|
||||
bot_id=bot_info.self_id,
|
||||
@@ -62,10 +63,7 @@ class BotManage:
|
||||
bot_info.connect_time = bot_live.get(bot.self_id) or 0
|
||||
if bot_info.connect_time:
|
||||
connect_date = datetime.fromtimestamp(CONNECT_TIME)
|
||||
connect_date_str = connect_date.strftime("%Y-%m-%d %H:%M:%S")
|
||||
bot_info.connect_date = datetime.strptime(
|
||||
connect_date_str, "%Y-%m-%d %H:%M:%S"
|
||||
)
|
||||
bot_info.connect_date = connect_date.strftime("%Y-%m-%d %H:%M:%S")
|
||||
return bot_info
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
@@ -22,5 +20,52 @@ class BotInfo(BaseModel):
|
||||
"""今日调用插件次数"""
|
||||
connect_time: int = 0
|
||||
"""连接时间"""
|
||||
connect_date: datetime | None = None
|
||||
connect_date: str | None = None
|
||||
"""连接日期"""
|
||||
|
||||
|
||||
class QueryChatCallCount(BaseModel):
|
||||
"""
|
||||
查询聊天/调用记录次数
|
||||
"""
|
||||
|
||||
chat_num: int
|
||||
"""聊天记录总数"""
|
||||
chat_day: int
|
||||
"""今日消息"""
|
||||
call_num: int
|
||||
"""调用记录总数"""
|
||||
call_day: int
|
||||
"""今日调用"""
|
||||
|
||||
|
||||
class ChatCallMonthCount(BaseModel):
|
||||
"""
|
||||
查询聊天/调用一个月记录次数
|
||||
"""
|
||||
|
||||
chat: list[int]
|
||||
"""一个月内聊天总数"""
|
||||
call: list[int]
|
||||
"""一个月内调用数据"""
|
||||
date: list[str]
|
||||
"""日期"""
|
||||
|
||||
|
||||
class AllChatAndCallCount(BaseModel):
|
||||
"""
|
||||
查询聊天/调用记录次数
|
||||
"""
|
||||
|
||||
chat_week: int
|
||||
"""一周内聊天次数"""
|
||||
chat_month: int
|
||||
"""一月内聊天次数"""
|
||||
chat_year: int
|
||||
"""一年内聊天次数"""
|
||||
call_week: int
|
||||
"""一周内调用次数"""
|
||||
call_month: int
|
||||
"""一月内调用次数"""
|
||||
call_year: int
|
||||
"""一年内调用次数"""
|
||||
|
||||
@@ -2,6 +2,7 @@ import nonebot
|
||||
from tortoise import Tortoise
|
||||
from nonebot.drivers import Driver
|
||||
from fastapi import Request, APIRouter
|
||||
from fastapi.responses import JSONResponse
|
||||
from tortoise.exceptions import OperationalError
|
||||
|
||||
from zhenxun.models.task_info import TaskInfo
|
||||
@@ -62,26 +63,40 @@ async def _():
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_table_list", dependencies=[authentication()], description="获取数据库表"
|
||||
"/get_table_list",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[list[dict]],
|
||||
response_class=JSONResponse,
|
||||
description="获取数据库表",
|
||||
)
|
||||
async def _() -> Result:
|
||||
async def _() -> Result[list[dict]]:
|
||||
db = Tortoise.get_connection("default")
|
||||
query = await db.execute_query_dict(SELECT_TABLE_SQL)
|
||||
return Result.ok(query)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_table_column", dependencies=[authentication()], description="获取表字段"
|
||||
"/get_table_column",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[list[dict]],
|
||||
response_class=JSONResponse,
|
||||
description="获取表字段",
|
||||
)
|
||||
async def _(table_name: str) -> Result:
|
||||
async def _(table_name: str) -> Result[list[dict]]:
|
||||
db = Tortoise.get_connection("default")
|
||||
# print(SELECT_TABLE_COLUMN_SQL.format(table_name))
|
||||
query = await db.execute_query_dict(SELECT_TABLE_COLUMN_SQL.format(table_name))
|
||||
return Result.ok(query)
|
||||
|
||||
|
||||
@router.post("/exec_sql", dependencies=[authentication()], description="执行sql")
|
||||
async def _(sql: SqlText, request: Request) -> Result:
|
||||
@router.post(
|
||||
"/exec_sql",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[list[dict]],
|
||||
response_class=JSONResponse,
|
||||
description="执行sql",
|
||||
)
|
||||
async def _(sql: SqlText, request: Request) -> Result[list[dict]]:
|
||||
ip = request.client.host if request.client else "unknown"
|
||||
try:
|
||||
if sql.sql.lower().startswith("select"):
|
||||
@@ -98,8 +113,14 @@ async def _(sql: SqlText, request: Request) -> Result:
|
||||
return Result.warning_(f"sql执行错误: {e}")
|
||||
|
||||
|
||||
@router.post("/get_sql_log", dependencies=[authentication()], description="sql日志列表")
|
||||
async def _(query: QueryModel) -> Result:
|
||||
@router.post(
|
||||
"/get_sql_log",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[BaseResultModel],
|
||||
response_class=JSONResponse,
|
||||
description="sql日志列表",
|
||||
)
|
||||
async def _(query: QueryModel) -> Result[BaseResultModel]:
|
||||
total = await SqlLog.all().count()
|
||||
if total % query.size:
|
||||
total += 1
|
||||
@@ -112,8 +133,14 @@ async def _(query: QueryModel) -> Result:
|
||||
return Result.ok(BaseResultModel(total=total, data=data))
|
||||
|
||||
|
||||
@router.get("/get_common_sql", dependencies=[authentication()], description="常用sql")
|
||||
async def _(plugin_name: str | None = None) -> Result:
|
||||
@router.get(
|
||||
"/get_common_sql",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[dict],
|
||||
response_class=JSONResponse,
|
||||
description="常用sql",
|
||||
)
|
||||
async def _(plugin_name: str | None = None) -> Result[dict]:
|
||||
if plugin_name:
|
||||
return Result.ok(SQL_DICT.get(plugin_name))
|
||||
return Result.ok(str(SQL_DICT))
|
||||
|
||||
@@ -6,31 +6,48 @@ from datetime import datetime, timedelta
|
||||
|
||||
import nonebot
|
||||
from fastapi import APIRouter
|
||||
from nonebot.config import Config
|
||||
from tortoise.functions import Count
|
||||
from fastapi.responses import JSONResponse
|
||||
from websockets.exceptions import ConnectionClosedOK, ConnectionClosedError
|
||||
from starlette.websockets import WebSocket, WebSocketState, WebSocketDisconnect
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.models.group_info import GroupInfo
|
||||
from zhenxun.models.statistics import Statistics
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
from zhenxun.models.plugin_info import PluginInfo
|
||||
from zhenxun.models.chat_history import ChatHistory
|
||||
from zhenxun.models.group_console import GroupConsole
|
||||
from zhenxun.models.bot_connect_log import BotConnectLog
|
||||
|
||||
from ....base_model import Result
|
||||
from .data_source import bot_live
|
||||
from ....utils import authentication, get_system_status
|
||||
from ....config import AVA_URL, GROUP_AVA_URL, QueryDateType
|
||||
from .model import BaseInfo, HotPlugin, ActiveGroup, ChatHistoryCount
|
||||
from .model import (
|
||||
BaseInfo,
|
||||
HotPlugin,
|
||||
QueryCount,
|
||||
ActiveGroup,
|
||||
NonebotData,
|
||||
TemplateBaseInfo,
|
||||
)
|
||||
|
||||
driver = nonebot.get_driver()
|
||||
run_time = time.time()
|
||||
|
||||
ws_router = APIRouter()
|
||||
router = APIRouter(prefix="/main")
|
||||
|
||||
|
||||
@router.get("/get_base_info", dependencies=[authentication()], description="基础信息")
|
||||
async def _(bot_id: str | None = None) -> Result:
|
||||
@router.get(
|
||||
"/get_base_info",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[list[BaseInfo]],
|
||||
response_class=JSONResponse,
|
||||
description="基础信息",
|
||||
)
|
||||
async def _(bot_id: str | None = None) -> Result[list[BaseInfo]]:
|
||||
"""获取Bot基础信息
|
||||
|
||||
参数:
|
||||
@@ -39,13 +56,14 @@ async def _(bot_id: str | None = None) -> Result:
|
||||
返回:
|
||||
Result: 获取指定bot信息与bot列表
|
||||
"""
|
||||
bot_list: list[BaseInfo] = []
|
||||
global run_time
|
||||
bot_list: list[TemplateBaseInfo] = []
|
||||
if bots := nonebot.get_bots():
|
||||
select_bot: BaseInfo
|
||||
for key, bot in bots.items():
|
||||
for _, bot in bots.items():
|
||||
login_info = await bot.get_login_info()
|
||||
bot_list.append(
|
||||
BaseInfo(
|
||||
TemplateBaseInfo(
|
||||
bot=bot, # type: ignore
|
||||
self_id=bot.self_id,
|
||||
nickname=login_info["nickname"],
|
||||
@@ -58,7 +76,6 @@ async def _(bot_id: str | None = None) -> Result:
|
||||
else:
|
||||
select_bot = bot_list[0]
|
||||
select_bot.is_select = True
|
||||
select_bot.config = select_bot.bot.config
|
||||
now = datetime.now()
|
||||
# 今日累计接收消息
|
||||
select_bot.received_messages = await ChatHistory.filter(
|
||||
@@ -82,10 +99,7 @@ async def _(bot_id: str | None = None) -> Result:
|
||||
select_bot.connect_time = bot_live.get(select_bot.self_id) or 0
|
||||
if select_bot.connect_time:
|
||||
connect_date = datetime.fromtimestamp(select_bot.connect_time)
|
||||
connect_date_str = connect_date.strftime("%Y-%m-%d %H:%M:%S")
|
||||
select_bot.connect_date = datetime.strptime(
|
||||
connect_date_str, "%Y-%m-%d %H:%M:%S"
|
||||
)
|
||||
select_bot.connect_date = connect_date.strftime("%Y-%m-%d %H:%M:%S")
|
||||
version_file = Path() / "__version__"
|
||||
if version_file.exists():
|
||||
if text := version_file.open().read():
|
||||
@@ -95,30 +109,40 @@ async def _(bot_id: str | None = None) -> Result:
|
||||
create_time__gte=now - timedelta(hours=now.hour)
|
||||
).count()
|
||||
select_bot.day_call = day_call
|
||||
return Result.ok(bot_list, "拿到信息啦!")
|
||||
select_bot.connect_count = await BotConnectLog.filter(
|
||||
bot_id=select_bot.self_id
|
||||
).count()
|
||||
return Result.ok([BaseInfo(**e.dict()) for e in bot_list], "拿到信息啦!")
|
||||
return Result.warning_("无Bot连接...")
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_all_ch_count", dependencies=[authentication()], description="获取接收消息数量"
|
||||
"/get_all_chat_count",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[QueryCount],
|
||||
response_class=JSONResponse,
|
||||
description="获取接收消息数量",
|
||||
)
|
||||
async def _(bot_id: str) -> Result:
|
||||
async def _(bot_id: str | None = None) -> Result[QueryCount]:
|
||||
now = datetime.now()
|
||||
all_count = await ChatHistory.filter(bot_id=bot_id).count()
|
||||
day_count = await ChatHistory.filter(
|
||||
bot_id=bot_id, create_time__gte=now - timedelta(hours=now.hour)
|
||||
query = ChatHistory
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
all_count = await query.annotate().count()
|
||||
day_count = await query.filter(
|
||||
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
week_count = await ChatHistory.filter(
|
||||
bot_id=bot_id, create_time__gte=now - timedelta(days=7)
|
||||
week_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
month_count = await ChatHistory.filter(
|
||||
bot_id=bot_id, create_time__gte=now - timedelta(days=30)
|
||||
month_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=30, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
year_count = await ChatHistory.filter(
|
||||
bot_id=bot_id, create_time__gte=now - timedelta(days=365)
|
||||
year_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=365, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
return Result.ok(
|
||||
ChatHistoryCount(
|
||||
QueryCount(
|
||||
num=all_count,
|
||||
day=day_count,
|
||||
week=week_count,
|
||||
@@ -129,44 +153,49 @@ async def _(bot_id: str) -> Result:
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_ch_count", dependencies=[authentication()], description="获取接收消息数量"
|
||||
"/get_all_call_count",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[QueryCount],
|
||||
response_class=JSONResponse,
|
||||
description="获取调用次数",
|
||||
)
|
||||
async def _(bot_id: str, query_type: QueryDateType | None = None) -> Result:
|
||||
if nonebot.get_bot(bot_id):
|
||||
if not query_type:
|
||||
return Result.ok(await ChatHistory.filter(bot_id=bot_id).count())
|
||||
now = datetime.now()
|
||||
if query_type == QueryDateType.DAY:
|
||||
return Result.ok(
|
||||
await ChatHistory.filter(
|
||||
bot_id=bot_id, create_time__gte=now - timedelta(hours=now.hour)
|
||||
).count()
|
||||
)
|
||||
if query_type == QueryDateType.WEEK:
|
||||
return Result.ok(
|
||||
await ChatHistory.filter(
|
||||
bot_id=bot_id, create_time__gte=now - timedelta(days=7)
|
||||
).count()
|
||||
)
|
||||
if query_type == QueryDateType.MONTH:
|
||||
return Result.ok(
|
||||
await ChatHistory.filter(
|
||||
bot_id=bot_id, create_time__gte=now - timedelta(days=30)
|
||||
).count()
|
||||
)
|
||||
if query_type == QueryDateType.YEAR:
|
||||
return Result.ok(
|
||||
await ChatHistory.filter(
|
||||
bot_id=bot_id, create_time__gte=now - timedelta(days=365)
|
||||
).count()
|
||||
)
|
||||
return Result.warning_("无Bot连接...")
|
||||
async def _(bot_id: str | None = None) -> Result[QueryCount]:
|
||||
now = datetime.now()
|
||||
query = Statistics
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
all_count = await query.annotate().count()
|
||||
day_count = await query.filter(
|
||||
create_time__gte=now - timedelta(hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
week_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=7, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
month_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=30, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
year_count = await query.filter(
|
||||
create_time__gte=now - timedelta(days=365, hours=now.hour, minutes=now.minute)
|
||||
).count()
|
||||
return Result.ok(
|
||||
QueryCount(
|
||||
num=all_count,
|
||||
day=day_count,
|
||||
week=week_count,
|
||||
month=month_count,
|
||||
year=year_count,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@router.get(
|
||||
"get_fg_count", dependencies=[authentication()], description="好友/群组数量"
|
||||
"get_fg_count",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[dict[str, int]],
|
||||
response_class=JSONResponse,
|
||||
description="好友/群组数量",
|
||||
)
|
||||
async def _(bot_id: str) -> Result:
|
||||
async def _(bot_id: str) -> Result[dict[str, int]]:
|
||||
if bots := nonebot.get_bots():
|
||||
if bot_id not in bots:
|
||||
return Result.warning_("指定Bot未连接...")
|
||||
@@ -183,26 +212,60 @@ async def _(bot_id: str) -> Result:
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_run_time", dependencies=[authentication()], description="获取nb运行时间"
|
||||
"/get_nb_data",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[NonebotData],
|
||||
response_class=JSONResponse,
|
||||
description="获取nb数据",
|
||||
)
|
||||
async def _() -> Result:
|
||||
return Result.ok(int(time.time() - run_time))
|
||||
async def _() -> Result[NonebotData]:
|
||||
return Result.ok(NonebotData(config=driver.config, run_time=int(run_time)))
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_active_group", dependencies=[authentication()], description="获取活跃群聊"
|
||||
"/get_nb_config",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[Config],
|
||||
response_class=JSONResponse,
|
||||
description="获取nb配置",
|
||||
)
|
||||
async def _(date_type: QueryDateType | None = None) -> Result:
|
||||
async def _() -> Result[Config]:
|
||||
return Result.ok(driver.config)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_run_time",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[int],
|
||||
response_class=JSONResponse,
|
||||
description="获取nb运行时间",
|
||||
)
|
||||
async def _() -> Result[int]:
|
||||
return Result.ok(int(run_time))
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_active_group",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[list[ActiveGroup]],
|
||||
response_class=JSONResponse,
|
||||
description="获取活跃群聊",
|
||||
)
|
||||
async def _(
|
||||
date_type: QueryDateType | None = None, bot_id: str | None = None
|
||||
) -> Result[list[ActiveGroup]]:
|
||||
query = ChatHistory
|
||||
now = datetime.now()
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
if date_type == QueryDateType.DAY:
|
||||
query = ChatHistory.filter(create_time__gte=now - timedelta(hours=now.hour))
|
||||
query = query.filter(create_time__gte=now - timedelta(hours=now.hour))
|
||||
if date_type == QueryDateType.WEEK:
|
||||
query = ChatHistory.filter(create_time__gte=now - timedelta(days=7))
|
||||
query = query.filter(create_time__gte=now - timedelta(days=7))
|
||||
if date_type == QueryDateType.MONTH:
|
||||
query = ChatHistory.filter(create_time__gte=now - timedelta(days=30))
|
||||
query = query.filter(create_time__gte=now - timedelta(days=30))
|
||||
if date_type == QueryDateType.YEAR:
|
||||
query = ChatHistory.filter(create_time__gte=now - timedelta(days=365))
|
||||
query = query.filter(create_time__gte=now - timedelta(days=365))
|
||||
data_list = (
|
||||
await query.annotate(count=Count("id"))
|
||||
.filter(group_id__not_isnull=True)
|
||||
@@ -213,7 +276,7 @@ async def _(date_type: QueryDateType | None = None) -> Result:
|
||||
)
|
||||
id2name = {}
|
||||
if data_list:
|
||||
if info_list := await GroupInfo.filter(
|
||||
if info_list := await GroupConsole.filter(
|
||||
group_id__in=[x[0] for x in data_list]
|
||||
).all():
|
||||
for group_info in info_list:
|
||||
@@ -236,19 +299,27 @@ async def _(date_type: QueryDateType | None = None) -> Result:
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_hot_plugin", dependencies=[authentication()], description="获取热门插件"
|
||||
"/get_hot_plugin",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[list[HotPlugin]],
|
||||
response_class=JSONResponse,
|
||||
description="获取热门插件",
|
||||
)
|
||||
async def _(date_type: QueryDateType | None = None) -> Result:
|
||||
async def _(
|
||||
date_type: QueryDateType | None = None, bot_id: str | None = None
|
||||
) -> Result[list[HotPlugin]]:
|
||||
query = Statistics
|
||||
now = datetime.now()
|
||||
if bot_id:
|
||||
query = query.filter(bot_id=bot_id)
|
||||
if date_type == QueryDateType.DAY:
|
||||
query = Statistics.filter(create_time__gte=now - timedelta(hours=now.hour))
|
||||
query = query.filter(create_time__gte=now - timedelta(hours=now.hour))
|
||||
if date_type == QueryDateType.WEEK:
|
||||
query = Statistics.filter(create_time__gte=now - timedelta(days=7))
|
||||
query = query.filter(create_time__gte=now - timedelta(days=7))
|
||||
if date_type == QueryDateType.MONTH:
|
||||
query = Statistics.filter(create_time__gte=now - timedelta(days=30))
|
||||
query = query.filter(create_time__gte=now - timedelta(days=30))
|
||||
if date_type == QueryDateType.YEAR:
|
||||
query = Statistics.filter(create_time__gte=now - timedelta(days=365))
|
||||
query = query.filter(create_time__gte=now - timedelta(days=365))
|
||||
data_list = (
|
||||
await query.annotate(count=Count("id"))
|
||||
.group_by("plugin_name")
|
||||
@@ -281,4 +352,3 @@ async def system_logs_realtime(websocket: WebSocket, sleep: int = 5):
|
||||
system_status = await get_system_status()
|
||||
await websocket.send_text(system_status.json())
|
||||
await asyncio.sleep(sleep)
|
||||
return
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import time
|
||||
|
||||
import nonebot
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
from nonebot.drivers import Driver
|
||||
from nonebot.adapters.onebot.v11 import Bot
|
||||
|
||||
driver: Driver = nonebot.get_driver()
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.config import Config
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class SystemStatus(BaseModel):
|
||||
@@ -20,8 +18,6 @@ class BaseInfo(BaseModel):
|
||||
基础信息
|
||||
"""
|
||||
|
||||
bot: Bot
|
||||
"""Bot"""
|
||||
self_id: str
|
||||
"""SELF ID"""
|
||||
nickname: str
|
||||
@@ -36,8 +32,10 @@ class BaseInfo(BaseModel):
|
||||
"""今日 累计接收消息"""
|
||||
connect_time: int = 0
|
||||
"""连接时间"""
|
||||
connect_date: datetime | None = None
|
||||
connect_date: str | None = None
|
||||
"""连接日期"""
|
||||
connect_count: int = 0
|
||||
"""连接次数"""
|
||||
|
||||
plugin_count: int = 0
|
||||
"""加载插件数量"""
|
||||
@@ -48,9 +46,6 @@ class BaseInfo(BaseModel):
|
||||
|
||||
is_select: bool = False
|
||||
"""当前选择"""
|
||||
|
||||
config: Config | None = None
|
||||
"""nb配置"""
|
||||
day_call: int = 0
|
||||
"""今日调用插件次数"""
|
||||
version: str = "unknown"
|
||||
@@ -60,7 +55,16 @@ class BaseInfo(BaseModel):
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
|
||||
class ChatHistoryCount(BaseModel):
|
||||
class TemplateBaseInfo(BaseInfo):
|
||||
"""
|
||||
基础信息
|
||||
"""
|
||||
|
||||
bot: Bot
|
||||
"""bot"""
|
||||
|
||||
|
||||
class QueryCount(BaseModel):
|
||||
"""
|
||||
聊天记录数量
|
||||
"""
|
||||
@@ -103,3 +107,10 @@ class HotPlugin(BaseModel):
|
||||
"""插件名称"""
|
||||
count: int
|
||||
"""调用次数"""
|
||||
|
||||
|
||||
class NonebotData(BaseModel):
|
||||
config: Config
|
||||
"""nb配置"""
|
||||
run_time: int
|
||||
"""运行时间"""
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import nonebot
|
||||
from fastapi import APIRouter
|
||||
from tortoise.functions import Count
|
||||
from fastapi.responses import JSONResponse
|
||||
from nonebot.adapters.onebot.v11 import ActionFailed
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
@@ -41,7 +42,11 @@ router = APIRouter(prefix="/manage")
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_group_list", dependencies=[authentication()], description="获取群组列表"
|
||||
"/get_group_list",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[list[GroupResult]],
|
||||
response_class=JSONResponse,
|
||||
description="获取群组列表",
|
||||
)
|
||||
async def _(bot_id: str) -> Result:
|
||||
"""
|
||||
@@ -65,9 +70,13 @@ async def _(bot_id: str) -> Result:
|
||||
|
||||
|
||||
@router.post(
|
||||
"/update_group", dependencies=[authentication()], description="修改群组信息"
|
||||
"/update_group",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[str],
|
||||
response_class=JSONResponse,
|
||||
description="修改群组信息",
|
||||
)
|
||||
async def _(group: UpdateGroup) -> Result:
|
||||
async def _(group: UpdateGroup) -> Result[str]:
|
||||
try:
|
||||
group_id = group.group_id
|
||||
if db_group := await GroupConsole.get_group(group_id):
|
||||
@@ -75,9 +84,11 @@ async def _(group: UpdateGroup) -> Result:
|
||||
db_group.level = group.level
|
||||
db_group.status = group.status
|
||||
if group.close_plugins:
|
||||
group.close_plugins = [f"<{module}" for module in group.close_plugins]
|
||||
db_group.block_plugin = ",".join(group.close_plugins) + ","
|
||||
if group.task:
|
||||
if block_task := [t for t in task_list if t not in group.task]:
|
||||
block_task = [f"<{module}" for module in block_task]
|
||||
db_group.block_task = ",".join(block_task) + "," # type: ignore
|
||||
await db_group.save(
|
||||
update_fields=["level", "status", "block_plugin", "block_task"]
|
||||
@@ -89,9 +100,13 @@ async def _(group: UpdateGroup) -> Result:
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_friend_list", dependencies=[authentication()], description="获取好友列表"
|
||||
"/get_friend_list",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[list[Friend]],
|
||||
response_class=JSONResponse,
|
||||
description="获取好友列表",
|
||||
)
|
||||
async def _(bot_id: str) -> Result:
|
||||
async def _(bot_id: str) -> Result[list[Friend]]:
|
||||
"""
|
||||
获取群信息
|
||||
"""
|
||||
@@ -116,9 +131,13 @@ async def _(bot_id: str) -> Result:
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_request_count", dependencies=[authentication()], description="获取请求数量"
|
||||
"/get_request_count",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[dict[str, int]],
|
||||
response_class=JSONResponse,
|
||||
description="获取请求数量",
|
||||
)
|
||||
async def _() -> Result:
|
||||
async def _() -> Result[dict[str, int]]:
|
||||
f_count = await FgRequest.filter(
|
||||
request_type=RequestType.FRIEND, handle_type__isnull=True
|
||||
).count()
|
||||
@@ -133,9 +152,13 @@ async def _() -> Result:
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_request_list", dependencies=[authentication()], description="获取请求列表"
|
||||
"/get_request_list",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[ReqResult],
|
||||
response_class=JSONResponse,
|
||||
description="获取请求列表",
|
||||
)
|
||||
async def _() -> Result:
|
||||
async def _() -> Result[ReqResult]:
|
||||
try:
|
||||
req_result = ReqResult()
|
||||
data_list = await FgRequest.filter(handle_type__isnull=True).all()
|
||||
@@ -177,7 +200,11 @@ async def _() -> Result:
|
||||
|
||||
|
||||
@router.post(
|
||||
"/clear_request", dependencies=[authentication()], description="清空请求列表"
|
||||
"/clear_request",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="清空请求列表",
|
||||
)
|
||||
async def _(cr: ClearRequest) -> Result:
|
||||
await FgRequest.filter(
|
||||
@@ -186,7 +213,13 @@ async def _(cr: ClearRequest) -> Result:
|
||||
return Result.ok(info="成功清除了数据!")
|
||||
|
||||
|
||||
@router.post("/refuse_request", dependencies=[authentication()], description="拒绝请求")
|
||||
@router.post(
|
||||
"/refuse_request",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="拒绝请求",
|
||||
)
|
||||
async def _(parma: HandleRequest) -> Result:
|
||||
try:
|
||||
if bots := nonebot.get_bots():
|
||||
@@ -207,14 +240,24 @@ async def _(parma: HandleRequest) -> Result:
|
||||
return Result.fail(f"{type(e)}: {e}")
|
||||
|
||||
|
||||
@router.post("/delete_request", dependencies=[authentication()], description="忽略请求")
|
||||
@router.post(
|
||||
"/delete_request",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="忽略请求",
|
||||
)
|
||||
async def _(parma: HandleRequest) -> Result:
|
||||
await FgRequest.ignore(parma.id)
|
||||
return Result.ok(info="成功处理了请求!")
|
||||
|
||||
|
||||
@router.post(
|
||||
"/approve_request", dependencies=[authentication()], description="同意请求"
|
||||
"/approve_request",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="同意请求",
|
||||
)
|
||||
async def _(parma: HandleRequest) -> Result:
|
||||
try:
|
||||
@@ -245,7 +288,13 @@ async def _(parma: HandleRequest) -> Result:
|
||||
return Result.fail(f"{type(e)}: {e}")
|
||||
|
||||
|
||||
@router.post("/leave_group", dependencies=[authentication()], description="退群")
|
||||
@router.post(
|
||||
"/leave_group",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="退群",
|
||||
)
|
||||
async def _(param: LeaveGroup) -> Result:
|
||||
try:
|
||||
if bots := nonebot.get_bots():
|
||||
@@ -264,7 +313,13 @@ async def _(param: LeaveGroup) -> Result:
|
||||
return Result.fail(f"{type(e)}: {e}")
|
||||
|
||||
|
||||
@router.post("/delete_friend", dependencies=[authentication()], description="删除好友")
|
||||
@router.post(
|
||||
"/delete_friend",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="删除好友",
|
||||
)
|
||||
async def _(param: DeleteFriend) -> Result:
|
||||
try:
|
||||
if bots := nonebot.get_bots():
|
||||
@@ -284,9 +339,13 @@ async def _(param: DeleteFriend) -> Result:
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_friend_detail", dependencies=[authentication()], description="获取好友详情"
|
||||
"/get_friend_detail",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[UserDetail],
|
||||
response_class=JSONResponse,
|
||||
description="获取好友详情",
|
||||
)
|
||||
async def _(bot_id: str, user_id: str) -> Result:
|
||||
async def _(bot_id: str, user_id: str) -> Result[UserDetail]:
|
||||
if bots := nonebot.get_bots():
|
||||
if bot_id in bots:
|
||||
if fd := [
|
||||
@@ -327,9 +386,13 @@ async def _(bot_id: str, user_id: str) -> Result:
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_group_detail", dependencies=[authentication()], description="获取群组详情"
|
||||
"/get_group_detail",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[GroupDetail],
|
||||
response_class=JSONResponse,
|
||||
description="获取群组详情",
|
||||
)
|
||||
async def _(bot_id: str, group_id: str) -> Result:
|
||||
async def _(bot_id: str, group_id: str) -> Result[GroupDetail]:
|
||||
if not (bots := nonebot.get_bots()):
|
||||
return Result.warning_("无Bot连接...")
|
||||
if bot_id not in bots:
|
||||
@@ -346,34 +409,46 @@ async def _(bot_id: str, group_id: str) -> Result:
|
||||
.values_list("plugin_name", "count")
|
||||
)
|
||||
like_plugin = {}
|
||||
plugins = await PluginInfo.all()
|
||||
plugins = await PluginInfo.get_plugins()
|
||||
module2name = {p.module: p.name for p in plugins}
|
||||
for data in like_plugin_list:
|
||||
name = module2name.get(data[0]) or data[0]
|
||||
like_plugin[name] = data[1]
|
||||
close_plugins = []
|
||||
close_plugins: list[Plugin] = []
|
||||
if group.block_plugin:
|
||||
for module in group.block_plugin.split(","):
|
||||
module_ = module.replace(":super", "")
|
||||
is_super_block = module.endswith(":super")
|
||||
plugin = Plugin(
|
||||
module=module_,
|
||||
plugin_name=module,
|
||||
is_super_block=is_super_block,
|
||||
)
|
||||
plugin.plugin_name = module2name.get(module) or module
|
||||
close_plugins.append(plugin)
|
||||
for module in group.block_plugin.replace("<", "").split(","):
|
||||
if module:
|
||||
plugin = Plugin(
|
||||
module=module,
|
||||
plugin_name=module,
|
||||
is_super_block=False,
|
||||
)
|
||||
plugin.plugin_name = module2name.get(module) or module
|
||||
close_plugins.append(plugin)
|
||||
exists_modules = [p.module for p in close_plugins]
|
||||
if group.superuser_block_plugin:
|
||||
for module in group.superuser_block_plugin.replace("<", "").split(","):
|
||||
if module and module not in exists_modules:
|
||||
plugin = Plugin(
|
||||
module=module,
|
||||
plugin_name=module,
|
||||
is_super_block=True,
|
||||
)
|
||||
plugin.plugin_name = module2name.get(module) or module
|
||||
close_plugins.append(plugin)
|
||||
all_task = await TaskInfo.annotate().values_list("module", "name")
|
||||
task_module2name = {x[0]: x[1] for x in all_task}
|
||||
task_list = []
|
||||
if group.block_task:
|
||||
split_task = group.block_task.split(",")
|
||||
if group.block_task or group.superuser_block_plugin:
|
||||
sbp = group.superuser_block_plugin.replace("<", "").split(",")
|
||||
split_task = group.block_task.replace("<", "").split(",")
|
||||
for task in all_task:
|
||||
task_list.append(
|
||||
Task(
|
||||
name=task[0],
|
||||
zh_name=task_module2name.get(task[0]) or task[0],
|
||||
status=task[0] not in split_task,
|
||||
status=task[0] not in split_task and task[0] not in sbp,
|
||||
is_super_block=task[0] in sbp,
|
||||
)
|
||||
)
|
||||
else:
|
||||
@@ -383,6 +458,7 @@ async def _(bot_id: str, group_id: str) -> Result:
|
||||
name=task[0],
|
||||
zh_name=task_module2name.get(task[0]) or task[0],
|
||||
status=True,
|
||||
is_super_block=False,
|
||||
)
|
||||
)
|
||||
group_detail = GroupDetail(
|
||||
@@ -403,7 +479,11 @@ async def _(bot_id: str, group_id: str) -> Result:
|
||||
|
||||
|
||||
@router.post(
|
||||
"/send_message", dependencies=[authentication()], description="获取群组详情"
|
||||
"/send_message",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="获取群组详情",
|
||||
)
|
||||
async def _(param: SendMessage) -> Result:
|
||||
if not (bots := nonebot.get_bots()):
|
||||
|
||||
@@ -29,6 +29,8 @@ class Task(BaseModel):
|
||||
"""被动中文名称"""
|
||||
status: bool
|
||||
"""状态"""
|
||||
is_super_block: bool
|
||||
"""是否超级用户禁用"""
|
||||
|
||||
|
||||
class Plugin(BaseModel):
|
||||
|
||||
@@ -2,6 +2,7 @@ import re
|
||||
|
||||
import cattrs
|
||||
from fastapi import Query, APIRouter
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.configs.config import Config
|
||||
@@ -25,11 +26,13 @@ router = APIRouter(prefix="/plugin")
|
||||
@router.get(
|
||||
"/get_plugin_list",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[list[PluginInfo]],
|
||||
response_class=JSONResponse,
|
||||
deprecated="获取插件列表", # type: ignore
|
||||
)
|
||||
async def _(
|
||||
plugin_type: list[PluginType] = Query(None), menu_type: str | None = None
|
||||
) -> Result:
|
||||
) -> Result[list[PluginInfo]]:
|
||||
try:
|
||||
plugin_list: list[PluginInfo] = []
|
||||
query = DbPluginInfo
|
||||
@@ -61,9 +64,11 @@ async def _(
|
||||
@router.get(
|
||||
"/get_plugin_count",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[int],
|
||||
response_class=JSONResponse,
|
||||
deprecated="获取插件数量", # type: ignore
|
||||
)
|
||||
async def _() -> Result:
|
||||
async def _() -> Result[int]:
|
||||
plugin_count = PluginCount()
|
||||
plugin_count.normal = await DbPluginInfo.filter(
|
||||
plugin_type=PluginType.NORMAL, load_status=True
|
||||
@@ -82,7 +87,11 @@ async def _() -> Result:
|
||||
|
||||
|
||||
@router.post(
|
||||
"/update_plugin", dependencies=[authentication()], description="更新插件参数"
|
||||
"/update_plugin",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="更新插件参数",
|
||||
)
|
||||
async def _(plugin: UpdatePlugin) -> Result:
|
||||
try:
|
||||
@@ -113,7 +122,13 @@ async def _(plugin: UpdatePlugin) -> Result:
|
||||
return Result.ok(info="已经帮你写好啦!")
|
||||
|
||||
|
||||
@router.post("/change_switch", dependencies=[authentication()], description="开关插件")
|
||||
@router.post(
|
||||
"/change_switch",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="开关插件",
|
||||
)
|
||||
async def _(param: PluginSwitch) -> Result:
|
||||
db_plugin = await DbPluginInfo.get_or_none(module=param.module, load_status=True)
|
||||
if not db_plugin:
|
||||
@@ -129,9 +144,13 @@ async def _(param: PluginSwitch) -> Result:
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_plugin_menu_type", dependencies=[authentication()], description="获取插件类型"
|
||||
"/get_plugin_menu_type",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[list[str]],
|
||||
response_class=JSONResponse,
|
||||
description="获取插件类型",
|
||||
)
|
||||
async def _() -> Result:
|
||||
async def _() -> Result[list[str]]:
|
||||
menu_type_list = []
|
||||
result = await DbPluginInfo.annotate().values_list("menu_type", flat=True)
|
||||
for r in result:
|
||||
@@ -140,8 +159,14 @@ async def _() -> Result:
|
||||
return Result.ok(menu_type_list)
|
||||
|
||||
|
||||
@router.get("/get_plugin", dependencies=[authentication()], description="获取插件详情")
|
||||
async def _(module: str) -> Result:
|
||||
@router.get(
|
||||
"/get_plugin",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[PluginDetail],
|
||||
response_class=JSONResponse,
|
||||
description="获取插件详情",
|
||||
)
|
||||
async def _(module: str) -> Result[PluginDetail]:
|
||||
db_plugin = await DbPluginInfo.get_or_none(module=module, load_status=True)
|
||||
if not db_plugin:
|
||||
return Result.fail("插件不存在...")
|
||||
|
||||
@@ -1,25 +1,37 @@
|
||||
from nonebot import require
|
||||
from fastapi import APIRouter
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from zhenxun.models.plugin_info import PluginInfo
|
||||
|
||||
from .model import PluginIr
|
||||
from ....base_model import Result
|
||||
from ....utils import authentication
|
||||
|
||||
require("plugin_store")
|
||||
from zhenxun.builtin_plugins.plugin_store import ShopManage
|
||||
|
||||
router = APIRouter(prefix="/store")
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_plugin_store",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[dict],
|
||||
response_class=JSONResponse,
|
||||
deprecated="获取插件商店插件信息", # type: ignore
|
||||
)
|
||||
async def _() -> Result:
|
||||
async def _() -> Result[dict]:
|
||||
try:
|
||||
require("plugin_store")
|
||||
from zhenxun.builtin_plugins.plugin_store import ShopManage
|
||||
|
||||
data = await ShopManage.get_data()
|
||||
return Result.ok(data)
|
||||
plugin_list = [
|
||||
{**data[name].dict(), "name": name, "id": idx}
|
||||
for idx, name in enumerate(data)
|
||||
]
|
||||
modules = await PluginInfo.filter(load_status=True).values_list(
|
||||
"module", flat=True
|
||||
)
|
||||
return Result.ok({"install_module": modules, "plugin_list": plugin_list})
|
||||
except Exception as e:
|
||||
return Result.fail(f"获取插件商店插件信息失败: {type(e)}: {e}")
|
||||
|
||||
@@ -27,24 +39,52 @@ async def _() -> Result:
|
||||
@router.post(
|
||||
"/install_plugin",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
deprecated="安装插件", # type: ignore
|
||||
)
|
||||
async def _(param: PluginIr) -> Result:
|
||||
try:
|
||||
require("plugin_store")
|
||||
from zhenxun.builtin_plugins.plugin_store import ShopManage
|
||||
|
||||
result = await ShopManage.add_plugin(param.id) # type: ignore
|
||||
return Result.ok(result)
|
||||
return Result.ok(info=result)
|
||||
except Exception as e:
|
||||
return Result.fail(f"安装插件失败: {type(e)}: {e}")
|
||||
|
||||
|
||||
@router.post(
|
||||
"/update_plugin",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
deprecated="更新插件", # type: ignore
|
||||
)
|
||||
async def _(param: PluginIr) -> Result:
|
||||
try:
|
||||
require("plugin_store")
|
||||
from zhenxun.builtin_plugins.plugin_store import ShopManage
|
||||
|
||||
result = await ShopManage.update_plugin(param.id) # type: ignore
|
||||
return Result.ok(info=result)
|
||||
except Exception as e:
|
||||
return Result.fail(f"更新插件失败: {type(e)}: {e}")
|
||||
|
||||
|
||||
@router.post(
|
||||
"/remove_plugin",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
deprecated="移除插件", # type: ignore
|
||||
)
|
||||
async def _(param: PluginIr) -> Result:
|
||||
try:
|
||||
require("plugin_store")
|
||||
from zhenxun.builtin_plugins.plugin_store import ShopManage
|
||||
|
||||
result = await ShopManage.remove_plugin(param.id) # type: ignore
|
||||
return Result.ok(result)
|
||||
return Result.ok(info=result)
|
||||
except Exception as e:
|
||||
return Result.fail(f"移除插件失败: {type(e)}: {e}")
|
||||
|
||||
@@ -4,10 +4,11 @@ from pathlib import Path
|
||||
|
||||
import aiofiles
|
||||
from fastapi import APIRouter
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
from zhenxun.utils._build_image import BuildImage
|
||||
|
||||
from ....base_model import Result
|
||||
from ....base_model import Result, SystemFolderSize
|
||||
from ....utils import authentication, get_system_disk
|
||||
from .model import AddFile, DirFile, SaveFile, DeleteFile, RenameFile
|
||||
|
||||
@@ -17,9 +18,13 @@ IMAGE_TYPE = ["jpg", "jpeg", "png", "gif", "bmp", "webp", "svg"]
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_dir_list", dependencies=[authentication()], description="获取文件列表"
|
||||
"/get_dir_list",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[list[DirFile]],
|
||||
response_class=JSONResponse,
|
||||
description="获取文件列表",
|
||||
)
|
||||
async def _(path: str | None = None) -> Result:
|
||||
async def _(path: str | None = None) -> Result[list[DirFile]]:
|
||||
base_path = Path(path) if path else Path()
|
||||
data_list = []
|
||||
for file in os.listdir(base_path):
|
||||
@@ -37,13 +42,23 @@ async def _(path: str | None = None) -> Result:
|
||||
|
||||
|
||||
@router.get(
|
||||
"/get_resources_size", dependencies=[authentication()], description="获取文件列表"
|
||||
"/get_resources_size",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[SystemFolderSize],
|
||||
response_class=JSONResponse,
|
||||
description="获取文件列表",
|
||||
)
|
||||
async def _(full_path: str | None = None) -> Result:
|
||||
async def _(full_path: str | None = None) -> Result[SystemFolderSize]:
|
||||
return Result.ok(await get_system_disk(full_path))
|
||||
|
||||
|
||||
@router.post("/delete_file", dependencies=[authentication()], description="删除文件")
|
||||
@router.post(
|
||||
"/delete_file",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="删除文件",
|
||||
)
|
||||
async def _(param: DeleteFile) -> Result:
|
||||
path = Path(param.full_path)
|
||||
if not path or not path.exists():
|
||||
@@ -56,7 +71,11 @@ async def _(param: DeleteFile) -> Result:
|
||||
|
||||
|
||||
@router.post(
|
||||
"/delete_folder", dependencies=[authentication()], description="删除文件夹"
|
||||
"/delete_folder",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="删除文件夹",
|
||||
)
|
||||
async def _(param: DeleteFile) -> Result:
|
||||
path = Path(param.full_path)
|
||||
@@ -69,7 +88,13 @@ async def _(param: DeleteFile) -> Result:
|
||||
return Result.warning_(f"删除失败: {e!s}")
|
||||
|
||||
|
||||
@router.post("/rename_file", dependencies=[authentication()], description="重命名文件")
|
||||
@router.post(
|
||||
"/rename_file",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="重命名文件",
|
||||
)
|
||||
async def _(param: RenameFile) -> Result:
|
||||
path = (
|
||||
(Path(param.parent) / param.old_name) if param.parent else Path(param.old_name)
|
||||
@@ -84,7 +109,11 @@ async def _(param: RenameFile) -> Result:
|
||||
|
||||
|
||||
@router.post(
|
||||
"/rename_folder", dependencies=[authentication()], description="重命名文件夹"
|
||||
"/rename_folder",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="重命名文件夹",
|
||||
)
|
||||
async def _(param: RenameFile) -> Result:
|
||||
path = (
|
||||
@@ -100,7 +129,13 @@ async def _(param: RenameFile) -> Result:
|
||||
return Result.warning_(f"重命名失败: {e!s}")
|
||||
|
||||
|
||||
@router.post("/add_file", dependencies=[authentication()], description="新建文件")
|
||||
@router.post(
|
||||
"/add_file",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="新建文件",
|
||||
)
|
||||
async def _(param: AddFile) -> Result:
|
||||
path = (Path(param.parent) / param.name) if param.parent else Path(param.name)
|
||||
if path.exists():
|
||||
@@ -112,7 +147,13 @@ async def _(param: AddFile) -> Result:
|
||||
return Result.warning_(f"新建文件失败: {e!s}")
|
||||
|
||||
|
||||
@router.post("/add_folder", dependencies=[authentication()], description="新建文件夹")
|
||||
@router.post(
|
||||
"/add_folder",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result,
|
||||
response_class=JSONResponse,
|
||||
description="新建文件夹",
|
||||
)
|
||||
async def _(param: AddFile) -> Result:
|
||||
path = (Path(param.parent) / param.name) if param.parent else Path(param.name)
|
||||
if path.exists():
|
||||
@@ -124,7 +165,13 @@ async def _(param: AddFile) -> Result:
|
||||
return Result.warning_(f"新建文件夹失败: {e!s}")
|
||||
|
||||
|
||||
@router.get("/read_file", dependencies=[authentication()], description="读取文件")
|
||||
@router.get(
|
||||
"/read_file",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[str],
|
||||
response_class=JSONResponse,
|
||||
description="读取文件",
|
||||
)
|
||||
async def _(full_path: str) -> Result:
|
||||
path = Path(full_path)
|
||||
if not path.exists():
|
||||
@@ -136,8 +183,14 @@ async def _(full_path: str) -> Result:
|
||||
return Result.warning_(f"读取文件失败: {e!s}")
|
||||
|
||||
|
||||
@router.post("/save_file", dependencies=[authentication()], description="读取文件")
|
||||
async def _(param: SaveFile) -> Result:
|
||||
@router.post(
|
||||
"/save_file",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[str],
|
||||
response_class=JSONResponse,
|
||||
description="读取文件",
|
||||
)
|
||||
async def _(param: SaveFile) -> Result[str]:
|
||||
path = Path(param.full_path)
|
||||
try:
|
||||
async with aiofiles.open(path, "w", encoding="utf-8") as f:
|
||||
@@ -147,8 +200,14 @@ async def _(param: SaveFile) -> Result:
|
||||
return Result.warning_(f"保存文件失败: {e!s}")
|
||||
|
||||
|
||||
@router.get("/get_image", dependencies=[authentication()], description="读取图片base64")
|
||||
async def _(full_path: str) -> Result:
|
||||
@router.get(
|
||||
"/get_image",
|
||||
dependencies=[authentication()],
|
||||
response_model=Result[str],
|
||||
response_class=JSONResponse,
|
||||
description="读取图片base64",
|
||||
)
|
||||
async def _(full_path: str) -> Result[str]:
|
||||
path = Path(full_path)
|
||||
if not path.exists():
|
||||
return Result.warning_("文件不存在...")
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from datetime import datetime
|
||||
from typing_extensions import Self
|
||||
from typing import Any, Generic, TypeVar
|
||||
|
||||
from pydantic import BaseModel, validator
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
RT = TypeVar("RT")
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
username: str
|
||||
@@ -17,7 +18,7 @@ class Token(BaseModel):
|
||||
token_type: str
|
||||
|
||||
|
||||
class Result(BaseModel):
|
||||
class Result(Generic[RT], BaseModel):
|
||||
"""
|
||||
总体返回
|
||||
"""
|
||||
@@ -30,19 +31,21 @@ class Result(BaseModel):
|
||||
"""info"""
|
||||
warning: str | None = None
|
||||
"""警告信息"""
|
||||
data: Any = None
|
||||
data: RT = None
|
||||
"""返回数据"""
|
||||
|
||||
@classmethod
|
||||
def warning_(cls, info: str, code: int = 200) -> Self:
|
||||
def warning_(cls, info: str, code: int = 200) -> "Result[RT]":
|
||||
return cls(suc=True, warning=info, code=code)
|
||||
|
||||
@classmethod
|
||||
def fail(cls, info: str = "异常错误", code: int = 500) -> Self:
|
||||
def fail(cls, info: str = "异常错误", code: int = 500) -> "Result[RT]":
|
||||
return cls(suc=False, info=info, code=code)
|
||||
|
||||
@classmethod
|
||||
def ok(cls, data: Any = None, info: str = "操作成功", code: int = 200) -> Self:
|
||||
def ok(
|
||||
cls, data: Any = None, info: str = "操作成功", code: int = 200
|
||||
) -> "Result[RT]":
|
||||
return cls(suc=True, info=info, code=code, data=data)
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,19 @@ class BotSetting(BaseModel):
|
||||
"""数据库链接"""
|
||||
platform_superusers: dict[str, list[str]] = {}
|
||||
"""平台超级用户"""
|
||||
qbot_id_data: dict[str, str] = {}
|
||||
"""官bot id:账号id"""
|
||||
|
||||
def get_qbot_uid(self, qbot_id: str) -> str | None:
|
||||
"""获取官bot账号id
|
||||
|
||||
参数:
|
||||
qbot_id: 官bot id
|
||||
|
||||
返回:
|
||||
str: 账号id
|
||||
"""
|
||||
return self.qbot_id_data.get(qbot_id)
|
||||
|
||||
def get_superuser(self, platform: str) -> list[str]:
|
||||
"""获取超级用户
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import time
|
||||
|
||||
from tortoise import fields
|
||||
from typing_extensions import Self
|
||||
|
||||
from zhenxun.services.db_context import Model
|
||||
from tortoise import fields
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.services.db_context import Model
|
||||
from zhenxun.utils.exception import UserAndGroupIsNone
|
||||
|
||||
|
||||
class BanConsole(Model):
|
||||
|
||||
id = fields.IntField(pk=True, generated=True, auto_increment=True)
|
||||
"""自增id"""
|
||||
user_id = fields.CharField(255, null=True)
|
||||
@@ -25,9 +24,9 @@ class BanConsole(Model):
|
||||
operator = fields.CharField(255)
|
||||
"""使用Ban命令的用户"""
|
||||
|
||||
class Meta:
|
||||
class Meta: # type: ignore
|
||||
table = "ban_console"
|
||||
table_description = ".ban/b了 封禁人员/群组数据表"
|
||||
table_description = "封禁人员/群组数据表"
|
||||
|
||||
@classmethod
|
||||
async def _get_data(cls, user_id: str | None, group_id: str | None) -> Self | None:
|
||||
@@ -45,16 +44,14 @@ class BanConsole(Model):
|
||||
"""
|
||||
if not user_id and not group_id:
|
||||
raise UserAndGroupIsNone()
|
||||
user = None
|
||||
if user_id:
|
||||
if group_id:
|
||||
user = await cls.get_or_none(user_id=user_id, group_id=group_id)
|
||||
else:
|
||||
user = await cls.get_or_none(user_id=user_id, group_id__isnull=True)
|
||||
return (
|
||||
await cls.get_or_none(user_id=user_id, group_id=group_id)
|
||||
if group_id
|
||||
else await cls.get_or_none(user_id=user_id, group_id__isnull=True)
|
||||
)
|
||||
else:
|
||||
if group_id:
|
||||
user = await cls.get_or_none(user_id__isnull=True, group_id=group_id)
|
||||
return user
|
||||
return await cls.get_or_none(user_id="", group_id=group_id)
|
||||
|
||||
@classmethod
|
||||
async def check_ban_level(
|
||||
@@ -91,7 +88,7 @@ class BanConsole(Model):
|
||||
返回:
|
||||
int: ban剩余时长,-1时为永久ban,0表示未被ban
|
||||
"""
|
||||
logger.debug(f"获取用户ban时长", target=f"{group_id}:{user_id}")
|
||||
logger.debug("获取用户ban时长", target=f"{group_id}:{user_id}")
|
||||
user = await cls._get_data(user_id, group_id)
|
||||
if not user and user_id:
|
||||
user = await cls._get_data(user_id, None)
|
||||
@@ -99,9 +96,7 @@ class BanConsole(Model):
|
||||
if user.duration == -1:
|
||||
return -1
|
||||
_time = time.time() - (user.ban_time + user.duration)
|
||||
if _time > 0:
|
||||
return 0
|
||||
return int(time.time() - user.ban_time - user.duration)
|
||||
return 0 if _time > 0 else int(time.time() - user.ban_time - user.duration)
|
||||
return 0
|
||||
|
||||
@classmethod
|
||||
@@ -114,7 +109,7 @@ class BanConsole(Model):
|
||||
返回:
|
||||
bool: 是否被ban
|
||||
"""
|
||||
logger.debug(f"检测是否被ban", target=f"{group_id}:{user_id}")
|
||||
logger.debug("检测是否被ban", target=f"{group_id}:{user_id}")
|
||||
if await cls.check_ban_time(user_id, group_id):
|
||||
return True
|
||||
else:
|
||||
@@ -143,8 +138,8 @@ class BanConsole(Model):
|
||||
f"封禁用户/群组,等级:{ban_level},时长: {duration}",
|
||||
target=f"{group_id}:{user_id}",
|
||||
)
|
||||
user = await cls._get_data(user_id, group_id)
|
||||
if user:
|
||||
target = await cls._get_data(user_id, group_id)
|
||||
if target:
|
||||
await cls.unban(user_id, group_id)
|
||||
await cls.create(
|
||||
user_id=user_id,
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
from tortoise import fields
|
||||
|
||||
from zhenxun.services.db_context import Model
|
||||
|
||||
|
||||
class BotConnectLog(Model):
|
||||
id = fields.IntField(pk=True, generated=True, auto_increment=True)
|
||||
"""自增id"""
|
||||
bot_id = fields.CharField(255, description="Bot id")
|
||||
"""Bot id"""
|
||||
platform = fields.CharField(255, null=True, description="平台")
|
||||
"""平台"""
|
||||
connect_time = fields.DatetimeField(description="连接时间")
|
||||
"""日期"""
|
||||
type = fields.IntField(null=True, description="1: 连接, 0: 断开")
|
||||
"""1: 连接, 0: 断开"""
|
||||
create_time = fields.DatetimeField(auto_now_add=True)
|
||||
"""创建时间"""
|
||||
|
||||
class Meta: # type: ignore
|
||||
table = "bot_connect_log"
|
||||
table_description = "bot连接表"
|
||||
+170
-12
@@ -9,7 +9,6 @@ from zhenxun.services.db_context import Model
|
||||
|
||||
|
||||
class GroupConsole(Model):
|
||||
|
||||
id = fields.IntField(pk=True, generated=True, auto_increment=True)
|
||||
"""自增id"""
|
||||
group_id = fields.CharField(255, description="群组id")
|
||||
@@ -34,8 +33,14 @@ class GroupConsole(Model):
|
||||
"""群认证标记"""
|
||||
block_plugin = fields.TextField(default="", description="禁用插件")
|
||||
"""禁用插件"""
|
||||
superuser_block_plugin = fields.TextField(
|
||||
default="", description="超级用户禁用插件"
|
||||
)
|
||||
"""超级用户禁用插件"""
|
||||
block_task = fields.TextField(default="", description="禁用插件")
|
||||
"""禁用插件"""
|
||||
superuser_block_task = fields.TextField(default="", description="超级用户禁用被动")
|
||||
"""超级用户禁用被动"""
|
||||
platform = fields.CharField(255, default="qq", description="所属平台")
|
||||
"""所属平台"""
|
||||
|
||||
@@ -53,6 +58,7 @@ class GroupConsole(Model):
|
||||
if modules := await TaskInfo.filter(default_status=False).values_list(
|
||||
"module", flat=True
|
||||
):
|
||||
modules = [f"<{module}" for module in modules]
|
||||
group.block_task = ",".join(modules) + "," # type: ignore
|
||||
await group.save(using_db=using_db, update_fields=["block_task"])
|
||||
return group
|
||||
@@ -73,6 +79,7 @@ class GroupConsole(Model):
|
||||
"module", flat=True
|
||||
)
|
||||
):
|
||||
modules = [f"<{module}" for module in modules]
|
||||
group.block_task = ",".join(modules) + "," # type: ignore
|
||||
await group.save(using_db=using_db, update_fields=["block_task"])
|
||||
return group, is_create
|
||||
@@ -93,6 +100,7 @@ class GroupConsole(Model):
|
||||
"module", flat=True
|
||||
)
|
||||
):
|
||||
modules = [f"<{module}" for module in modules]
|
||||
group.block_task = ",".join(modules) + "," # type: ignore
|
||||
await group.save(using_db=using_db, update_fields=["block_task"])
|
||||
return group, is_create
|
||||
@@ -127,27 +135,94 @@ class GroupConsole(Model):
|
||||
return group.is_super if (group := await cls.get_group(group_id)) else False
|
||||
|
||||
@classmethod
|
||||
async def is_super_block_plugin(
|
||||
cls, group_id: str, module: str, channel_id: str | None = None
|
||||
) -> bool:
|
||||
async def is_superuser_block_plugin(cls, group_id: str, module: str) -> bool:
|
||||
"""查看群组是否超级用户禁用功能
|
||||
|
||||
参数:
|
||||
group_id: 群组id
|
||||
module: 模块名称
|
||||
channel_id: 频道id
|
||||
|
||||
返回:
|
||||
bool: 是否禁用被动
|
||||
"""
|
||||
return await cls.exists(
|
||||
group_id=group_id,
|
||||
channel_id=channel_id,
|
||||
block_plugin__contains=f"super:{module},",
|
||||
superuser_block_plugin__contains=f"<{module},",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def is_block_plugin(
|
||||
async def is_block_plugin(cls, group_id: str, module: str) -> bool:
|
||||
"""查看群组是否禁用插件
|
||||
|
||||
参数:
|
||||
group_id: 群组id
|
||||
plugin: 插件名称
|
||||
|
||||
返回:
|
||||
bool: 是否禁用插件
|
||||
"""
|
||||
return await cls.exists(
|
||||
group_id=group_id, block_plugin__contains=f"<{module},"
|
||||
) or await cls.exists(
|
||||
group_id=group_id, superuser_block_plugin__contains=f"<{module},"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def set_block_plugin(
|
||||
cls,
|
||||
group_id: str,
|
||||
module: str,
|
||||
is_superuser: bool = False,
|
||||
platform: str | None = None,
|
||||
):
|
||||
"""禁用群组插件
|
||||
|
||||
参数:
|
||||
group_id: 群组id
|
||||
task: 任务模块
|
||||
is_superuser: 是否为超级用户
|
||||
platform: 平台
|
||||
"""
|
||||
group, _ = await cls.get_or_create(
|
||||
group_id=group_id, defaults={"platform": platform}
|
||||
)
|
||||
if is_superuser:
|
||||
if f"<{module}," not in group.superuser_block_plugin:
|
||||
group.superuser_block_plugin += f"<{module},"
|
||||
elif f"<{module}," not in group.block_plugin:
|
||||
group.block_plugin += f"<{module},"
|
||||
await group.save(update_fields=["block_plugin", "superuser_block_plugin"])
|
||||
|
||||
@classmethod
|
||||
async def set_unblock_plugin(
|
||||
cls,
|
||||
group_id: str,
|
||||
module: str,
|
||||
is_superuser: bool = False,
|
||||
platform: str | None = None,
|
||||
):
|
||||
"""禁用群组插件
|
||||
|
||||
参数:
|
||||
group_id: 群组id
|
||||
task: 任务模块
|
||||
is_superuser: 是否为超级用户
|
||||
platform: 平台
|
||||
"""
|
||||
group, _ = await cls.get_or_create(
|
||||
group_id=group_id, defaults={"platform": platform}
|
||||
)
|
||||
if is_superuser:
|
||||
if f"<{module}," in group.superuser_block_plugin:
|
||||
group.superuser_block_plugin = group.superuser_block_plugin.replace(
|
||||
f"<{module},", ""
|
||||
)
|
||||
elif f"<{module}," in group.block_plugin:
|
||||
group.block_plugin = group.block_plugin.replace(f"<{module},", "")
|
||||
await group.save(update_fields=["block_plugin", "superuser_block_plugin"])
|
||||
|
||||
@classmethod
|
||||
async def is_normal_block_plugin(
|
||||
cls, group_id: str, module: str, channel_id: str | None = None
|
||||
) -> bool:
|
||||
"""查看群组是否禁用功能
|
||||
@@ -163,7 +238,23 @@ class GroupConsole(Model):
|
||||
return await cls.exists(
|
||||
group_id=group_id,
|
||||
channel_id=channel_id,
|
||||
block_plugin__contains=f"{module},",
|
||||
block_plugin__contains=f"<{module},",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def is_superuser_block_task(cls, group_id: str, task: str) -> bool:
|
||||
"""查看群组是否超级用户禁用被动
|
||||
|
||||
参数:
|
||||
group_id: 群组id
|
||||
task: 模块名称
|
||||
|
||||
返回:
|
||||
bool: 是否禁用被动
|
||||
"""
|
||||
return await cls.exists(
|
||||
group_id=group_id,
|
||||
superuser_block_task__contains=f"<{task},",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@@ -184,12 +275,79 @@ class GroupConsole(Model):
|
||||
return await cls.exists(
|
||||
group_id=group_id,
|
||||
channel_id__isnull=True,
|
||||
block_task__contains=f"{task},",
|
||||
block_task__contains=f"<{task},",
|
||||
) or await cls.exists(
|
||||
group_id=group_id,
|
||||
channel_id__isnull=True,
|
||||
superuser_block_task__contains=f"<{task},",
|
||||
)
|
||||
return await cls.exists(
|
||||
group_id=group_id, channel_id=channel_id, block_task__contains=f"{task},"
|
||||
group_id=group_id, channel_id=channel_id, block_task__contains=f"<{task},"
|
||||
) or await cls.exists(
|
||||
group_id=group_id,
|
||||
channel_id__isnull=True,
|
||||
superuser_block_task__contains=f"<{task},",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def set_block_task(
|
||||
cls,
|
||||
group_id: str,
|
||||
task: str,
|
||||
is_superuser: bool = False,
|
||||
platform: str | None = None,
|
||||
):
|
||||
"""禁用群组插件
|
||||
|
||||
参数:
|
||||
group_id: 群组id
|
||||
task: 任务模块
|
||||
is_superuser: 是否为超级用户
|
||||
platform: 平台
|
||||
"""
|
||||
group, _ = await cls.get_or_create(
|
||||
group_id=group_id, defaults={"platform": platform}
|
||||
)
|
||||
if is_superuser:
|
||||
if f"<{task}," not in group.superuser_block_task:
|
||||
group.superuser_block_task += f"<{task},"
|
||||
elif f"<{task}," not in group.block_task:
|
||||
group.block_task += f"<{task},"
|
||||
await group.save(update_fields=["block_task", "superuser_block_task"])
|
||||
|
||||
@classmethod
|
||||
async def set_unblock_task(
|
||||
cls,
|
||||
group_id: str,
|
||||
task: str,
|
||||
is_superuser: bool = False,
|
||||
platform: str | None = None,
|
||||
):
|
||||
"""禁用群组插件
|
||||
|
||||
参数:
|
||||
group_id: 群组id
|
||||
task: 任务模块
|
||||
is_superuser: 是否为超级用户
|
||||
platform: 平台
|
||||
"""
|
||||
group, _ = await cls.get_or_create(
|
||||
group_id=group_id, defaults={"platform": platform}
|
||||
)
|
||||
if is_superuser:
|
||||
if f"<{task}," in group.superuser_block_task:
|
||||
group.superuser_block_task = group.superuser_block_task.replace(
|
||||
f"<{task},", ""
|
||||
)
|
||||
elif f"<{task}," in group.block_task:
|
||||
group.block_task = group.block_task.replace(f"<{task},", "")
|
||||
await group.save(update_fields=["block_task", "superuser_block_task"])
|
||||
|
||||
@classmethod
|
||||
def _run_script(cls):
|
||||
return []
|
||||
return [
|
||||
"ALTER TABLE group_console ADD superuser_block_plugin"
|
||||
" character varying(255) NOT NULL DEFAULT '';",
|
||||
"ALTER TABLE group_console ADD superuser_block_task"
|
||||
" character varying(255) NOT NULL DEFAULT '';",
|
||||
]
|
||||
|
||||
@@ -23,7 +23,7 @@ class GroupInfo(Model):
|
||||
platform = fields.CharField(255, default="qq", description="所属平台")
|
||||
"""所属平台"""
|
||||
|
||||
class Meta:
|
||||
class Meta: # type: ignore
|
||||
table = "group_info"
|
||||
table_description = "群聊信息表"
|
||||
|
||||
@@ -40,12 +40,81 @@ class GroupInfo(Model):
|
||||
"""
|
||||
return await cls.exists(group_id=group_id, block_task__contains=f"{task},")
|
||||
|
||||
@classmethod
|
||||
async def is_block_plugin(cls, group_id: str, module: str) -> bool:
|
||||
"""查看群组是否禁用插件
|
||||
|
||||
参数:
|
||||
group_id: 群组id
|
||||
plugin: 插件名称
|
||||
|
||||
返回:
|
||||
bool: 是否禁用插件
|
||||
"""
|
||||
return await cls.exists(
|
||||
group_id=group_id, block_plugin__contains=f"{module},"
|
||||
) or await cls.exists(
|
||||
group_id=group_id, superuser_block_plugin__contains=f"{module},"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def set_block_plugin(
|
||||
cls,
|
||||
group_id: str,
|
||||
module: str,
|
||||
is_superuser: bool = False,
|
||||
platform: str | None = None,
|
||||
):
|
||||
"""禁用群组插件
|
||||
|
||||
参数:
|
||||
group_id: 群组id
|
||||
task: 任务模块
|
||||
"""
|
||||
group, _ = await cls.get_or_create(
|
||||
group_id=group_id, defaults={"platform": platform}
|
||||
)
|
||||
if is_superuser:
|
||||
if "module," not in group.superuser_block_plugin:
|
||||
group.superuser_block_plugin += f"{module},"
|
||||
elif "module," not in group.block_plugin:
|
||||
group.block_plugin += f"{module},"
|
||||
await group.save(update_fields=["block_plugin", "superuser_block_plugin"])
|
||||
|
||||
@classmethod
|
||||
async def set_unblock_plugin(
|
||||
cls,
|
||||
group_id: str,
|
||||
module: str,
|
||||
is_superuser: bool = False,
|
||||
platform: str | None = None,
|
||||
):
|
||||
"""禁用群组插件
|
||||
|
||||
参数:
|
||||
group_id: 群组id
|
||||
task: 任务模块
|
||||
"""
|
||||
group, _ = await cls.get_or_create(
|
||||
group_id=group_id, defaults={"platform": platform}
|
||||
)
|
||||
if is_superuser:
|
||||
if "module," in group.superuser_block_plugin:
|
||||
group.superuser_block_plugin = group.superuser_block_plugin.replace(
|
||||
f"{module},", ""
|
||||
)
|
||||
elif "module," in group.block_plugin:
|
||||
group.block_plugin = group.block_plugin.replace(f"{module},", "")
|
||||
await group.save(update_fields=["block_plugin", "superuser_block_plugin"])
|
||||
|
||||
@classmethod
|
||||
def _run_script(cls):
|
||||
return [
|
||||
"ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;", # group_info表添加一个group_flag
|
||||
"ALTER TABLE group_info ADD group_flag Integer NOT NULL DEFAULT 0;",
|
||||
# group_info表添加一个group_flag
|
||||
"ALTER TABLE group_info ALTER COLUMN group_id TYPE character varying(255);",
|
||||
"ALTER TABLE group_info ADD block_plugin Text NOT NULL DEFAULT '';",
|
||||
"ALTER TABLE group_info ADD block_task Text NOT NULL DEFAULT '';",
|
||||
"ALTER TABLE group_info ADD platform character varying(255) NOT NULL DEFAULT 'qq';",
|
||||
"ALTER TABLE group_info ADD platform character varying(255) NOT NULL"
|
||||
" DEFAULT 'qq';",
|
||||
]
|
||||
|
||||
@@ -4,7 +4,6 @@ from zhenxun.services.db_context import Model
|
||||
|
||||
|
||||
class Statistics(Model):
|
||||
|
||||
id = fields.IntField(pk=True, generated=True, auto_increment=True)
|
||||
"""自增id"""
|
||||
user_id = fields.CharField(255)
|
||||
@@ -15,15 +14,19 @@ class Statistics(Model):
|
||||
"""插件名称"""
|
||||
create_time = fields.DatetimeField(auto_now=True)
|
||||
"""添加日期"""
|
||||
bot_id = fields.CharField(255, null=True)
|
||||
"""Bot Id"""
|
||||
|
||||
class Meta:
|
||||
class Meta: # type: ignore
|
||||
table = "statistics"
|
||||
table_description = "插件调用统计数据库"
|
||||
|
||||
@classmethod
|
||||
async def _run_script(cls):
|
||||
return [
|
||||
"ALTER TABLE statistics RENAME COLUMN user_qq TO user_id;", # 将user_qq改为user_id
|
||||
"ALTER TABLE statistics RENAME COLUMN user_qq TO user_id;",
|
||||
# 将user_qq改为user_id
|
||||
"ALTER TABLE statistics ALTER COLUMN user_id TYPE character varying(255);",
|
||||
"ALTER TABLE statistics ALTER COLUMN group_id TYPE character varying(255);",
|
||||
"ALTER TABLE statistics ADD bot_id Text DEFAULT '';",
|
||||
]
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
from .db_context import *
|
||||
from .log import *
|
||||
|
||||
@@ -4,13 +4,11 @@ from tortoise.models import Model as Model_
|
||||
from nonebot.utils import is_coroutine_callable
|
||||
|
||||
from zhenxun.configs.config import BotConfig
|
||||
from zhenxun.configs.path_config import DATA_PATH
|
||||
|
||||
from .log import logger
|
||||
|
||||
SCRIPT_METHOD = []
|
||||
MODELS: list[str] = []
|
||||
DATABASE_SETTING_FILE = DATA_PATH / "database.json"
|
||||
|
||||
|
||||
class Model(Model_):
|
||||
|
||||
+93
-18
@@ -1,12 +1,13 @@
|
||||
from typing import Any, overload
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any, Dict, overload
|
||||
|
||||
from nonebot import require
|
||||
|
||||
require("nonebot_plugin_session")
|
||||
from loguru import logger as logger_
|
||||
from nonebot.log import default_filter, default_format
|
||||
from nonebot_plugin_session import Session
|
||||
from nonebot.log import default_filter, default_format
|
||||
from nonebot_plugin_uninfo import Session as uninfoSession
|
||||
|
||||
from zhenxun.configs.path_config import LOG_PATH
|
||||
|
||||
@@ -33,8 +34,10 @@ class logger:
|
||||
TEMPLATE_A = "Adapter[{}] {}"
|
||||
TEMPLATE_B = "Adapter[{}] [<u><c>{}</c></u>]: {}"
|
||||
TEMPLATE_C = "Adapter[{}] 用户[<u><e>{}</e></u>] 触发 [<u><c>{}</c></u>]: {}"
|
||||
TEMPLATE_D = "Adapter[{}] 群聊[<u><e>{}</e></u>] 用户[<u><e>{}</e></u>] 触发 [<u><c>{}</c></u>]: {}"
|
||||
TEMPLATE_E = "Adapter[{}] 群聊[<u><e>{}</e></u>] 用户[<u><e>{}</e></u>] 触发 [<u><c>{}</c></u>] [Target](<u><e>{}</e></u>): {}"
|
||||
TEMPLATE_D = "Adapter[{}] 群聊[<u><e>{}</e></u>] 用户[<u><e>{}</e></u>] 触发"
|
||||
" [<u><c>{}</c></u>]: {}"
|
||||
TEMPLATE_E = "Adapter[{}] 群聊[<u><e>{}</e></u>] 用户[<u><e>{}</e></u>] 触发"
|
||||
" [<u><c>{}</c></u>] [Target](<u><e>{}</e></u>): {}"
|
||||
|
||||
TEMPLATE_ADAPTER = "Adapter[<m>{}</m>] "
|
||||
TEMPLATE_USER = "用户[<u><e>{}</e></u>] "
|
||||
@@ -75,21 +78,32 @@ class logger:
|
||||
platform: str | None = None,
|
||||
): ...
|
||||
|
||||
@overload
|
||||
@classmethod
|
||||
def info(
|
||||
cls,
|
||||
info: str,
|
||||
command: str | None = None,
|
||||
*,
|
||||
session: int | str | Session | None = None,
|
||||
session: uninfoSession | None = None,
|
||||
target: Any = None,
|
||||
platform: str | None = None,
|
||||
): ...
|
||||
|
||||
@classmethod
|
||||
def info(
|
||||
cls,
|
||||
info: str,
|
||||
command: str | None = None,
|
||||
*,
|
||||
session: int | str | Session | uninfoSession | None = None,
|
||||
group_id: int | str | None = None,
|
||||
adapter: str | None = None,
|
||||
target: Any = None,
|
||||
platform: str | None = None,
|
||||
):
|
||||
user_id: str | None = session # type: ignore
|
||||
group_id = None
|
||||
if type(session) == Session:
|
||||
if isinstance(session, Session):
|
||||
user_id = session.id1
|
||||
adapter = session.bot_type
|
||||
if session.id3:
|
||||
@@ -97,12 +111,18 @@ class logger:
|
||||
elif session.id2:
|
||||
group_id = f"{session.id2}"
|
||||
platform = platform or session.platform
|
||||
elif isinstance(session, uninfoSession):
|
||||
user_id = session.user.id
|
||||
adapter = session.adapter
|
||||
if session.group:
|
||||
group_id = session.group.id
|
||||
platform = session.basic["scope"]
|
||||
template = cls.__parser_template(
|
||||
info, command, user_id, group_id, adapter, target, platform
|
||||
)
|
||||
try:
|
||||
logger_.opt(colors=True).info(template)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
logger_.info(template)
|
||||
|
||||
@classmethod
|
||||
@@ -110,7 +130,7 @@ class logger:
|
||||
cls,
|
||||
info: str,
|
||||
command: str,
|
||||
param: Dict[str, Any] | None = None,
|
||||
param: dict[str, Any] | None = None,
|
||||
result: str = "",
|
||||
):
|
||||
param_str = ""
|
||||
@@ -149,13 +169,27 @@ class logger:
|
||||
e: Exception | None = None,
|
||||
): ...
|
||||
|
||||
@overload
|
||||
@classmethod
|
||||
def warning(
|
||||
cls,
|
||||
info: str,
|
||||
command: str | None = None,
|
||||
*,
|
||||
session: int | str | Session | None = None,
|
||||
session: uninfoSession | None = None,
|
||||
adapter: str | None = None,
|
||||
target: Any = None,
|
||||
platform: str | None = None,
|
||||
e: Exception | None = None,
|
||||
): ...
|
||||
|
||||
@classmethod
|
||||
def warning(
|
||||
cls,
|
||||
info: str,
|
||||
command: str | None = None,
|
||||
*,
|
||||
session: int | str | Session | uninfoSession | None = None,
|
||||
group_id: int | str | None = None,
|
||||
adapter: str | None = None,
|
||||
target: Any = None,
|
||||
@@ -163,8 +197,7 @@ class logger:
|
||||
e: Exception | None = None,
|
||||
):
|
||||
user_id: str | None = session # type: ignore
|
||||
group_id = None
|
||||
if type(session) == Session:
|
||||
if isinstance(session, Session):
|
||||
user_id = session.id1
|
||||
adapter = session.bot_type
|
||||
if session.id3:
|
||||
@@ -172,6 +205,12 @@ class logger:
|
||||
elif session.id2:
|
||||
group_id = f"{session.id2}"
|
||||
platform = platform or session.platform
|
||||
elif isinstance(session, uninfoSession):
|
||||
user_id = session.user.id
|
||||
adapter = session.adapter
|
||||
if session.group:
|
||||
group_id = session.group.id
|
||||
platform = session.basic["scope"]
|
||||
template = cls.__parser_template(
|
||||
info, command, user_id, group_id, adapter, target, platform
|
||||
)
|
||||
@@ -210,13 +249,26 @@ class logger:
|
||||
e: Exception | None = None,
|
||||
): ...
|
||||
|
||||
@overload
|
||||
@classmethod
|
||||
def error(
|
||||
cls,
|
||||
info: str,
|
||||
command: str | None = None,
|
||||
*,
|
||||
session: int | str | Session | None = None,
|
||||
session: uninfoSession | None = None,
|
||||
target: Any = None,
|
||||
platform: str | None = None,
|
||||
e: Exception | None = None,
|
||||
): ...
|
||||
|
||||
@classmethod
|
||||
def error(
|
||||
cls,
|
||||
info: str,
|
||||
command: str | None = None,
|
||||
*,
|
||||
session: int | str | Session | uninfoSession | None = None,
|
||||
group_id: int | str | None = None,
|
||||
adapter: str | None = None,
|
||||
target: Any = None,
|
||||
@@ -224,8 +276,7 @@ class logger:
|
||||
e: Exception | None = None,
|
||||
):
|
||||
user_id: str | None = session # type: ignore
|
||||
group_id = None
|
||||
if type(session) == Session:
|
||||
if isinstance(session, Session):
|
||||
user_id = session.id1
|
||||
adapter = session.bot_type
|
||||
if session.id3:
|
||||
@@ -233,6 +284,12 @@ class logger:
|
||||
elif session.id2:
|
||||
group_id = f"{session.id2}"
|
||||
platform = platform or session.platform
|
||||
elif isinstance(session, uninfoSession):
|
||||
user_id = session.user.id
|
||||
adapter = session.adapter
|
||||
if session.group:
|
||||
group_id = session.group.id
|
||||
platform = session.basic["scope"]
|
||||
template = cls.__parser_template(
|
||||
info, command, user_id, group_id, adapter, target, platform
|
||||
)
|
||||
@@ -271,13 +328,26 @@ class logger:
|
||||
e: Exception | None = None,
|
||||
): ...
|
||||
|
||||
@overload
|
||||
@classmethod
|
||||
def debug(
|
||||
cls,
|
||||
info: str,
|
||||
command: str | None = None,
|
||||
*,
|
||||
session: int | str | Session | None = None,
|
||||
session: uninfoSession | None = None,
|
||||
target: Any = None,
|
||||
platform: str | None = None,
|
||||
e: Exception | None = None,
|
||||
): ...
|
||||
|
||||
@classmethod
|
||||
def debug(
|
||||
cls,
|
||||
info: str,
|
||||
command: str | None = None,
|
||||
*,
|
||||
session: int | str | Session | uninfoSession | None = None,
|
||||
group_id: int | str | None = None,
|
||||
adapter: str | None = None,
|
||||
target: Any = None,
|
||||
@@ -285,8 +355,7 @@ class logger:
|
||||
e: Exception | None = None,
|
||||
):
|
||||
user_id: str | None = session # type: ignore
|
||||
group_id = None
|
||||
if type(session) == Session:
|
||||
if isinstance(session, Session):
|
||||
user_id = session.id1
|
||||
adapter = session.bot_type
|
||||
if session.id3:
|
||||
@@ -294,6 +363,12 @@ class logger:
|
||||
elif session.id2:
|
||||
group_id = f"{session.id2}"
|
||||
platform = platform or session.platform
|
||||
elif isinstance(session, uninfoSession):
|
||||
user_id = session.user.id
|
||||
adapter = session.adapter
|
||||
if session.group:
|
||||
group_id = session.group.id
|
||||
platform = session.basic["scope"]
|
||||
template = cls.__parser_template(
|
||||
info, command, user_id, group_id, adapter, target, platform
|
||||
)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot_plugin_uninfo import Uninfo, Session, SupportScope, get_interface
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.configs.config import BotConfig
|
||||
from zhenxun.models.task_info import TaskInfo
|
||||
@@ -6,9 +9,10 @@ from zhenxun.models.group_console import GroupConsole
|
||||
|
||||
|
||||
class CommonUtils:
|
||||
|
||||
@classmethod
|
||||
async def task_is_block(cls, module: str, group_id: str | None) -> bool:
|
||||
async def task_is_block(
|
||||
cls, session: Uninfo | Bot, module: str, group_id: str | None = None
|
||||
) -> bool:
|
||||
"""判断被动技能是否可以发送
|
||||
|
||||
参数:
|
||||
@@ -18,6 +22,19 @@ class CommonUtils:
|
||||
返回:
|
||||
bool: 是否可以发送
|
||||
"""
|
||||
if isinstance(session, Bot):
|
||||
if interface := get_interface(session):
|
||||
info = interface.basic_info()
|
||||
if info["scope"] == SupportScope.qq_api:
|
||||
logger.info("q官bot放弃所有被动技能发言...")
|
||||
"""q官bot放弃所有被动技能发言"""
|
||||
return False
|
||||
if session.scene == SupportScope.qq_api:
|
||||
"""q官bot放弃所有被动技能发言"""
|
||||
logger.info("q官bot放弃所有被动技能发言...")
|
||||
return False
|
||||
if not group_id and isinstance(session, Session):
|
||||
group_id = session.group.id if session.group else None
|
||||
if task := await TaskInfo.get_or_none(module=module):
|
||||
"""被动全局状态"""
|
||||
if not task.status:
|
||||
@@ -39,7 +56,6 @@ class CommonUtils:
|
||||
|
||||
|
||||
class SqlUtils:
|
||||
|
||||
@classmethod
|
||||
def random(cls, query, limit: int = 1) -> str:
|
||||
db_class_name = BotConfig.get_sql_type()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from typing import Any
|
||||
|
||||
from nonebot.internal.params import Depends
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot.params import Command
|
||||
from nonebot.matcher import Matcher
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from nonebot.internal.params import Depends
|
||||
from nonebot_plugin_session import EventSession
|
||||
from nonebot_plugin_userinfo import EventUserInfo, UserInfo
|
||||
|
||||
from zhenxun.configs.config import Config
|
||||
from zhenxun.utils.message import MessageUtils
|
||||
@@ -49,10 +49,8 @@ def UserName():
|
||||
用户名称
|
||||
"""
|
||||
|
||||
async def dependency(user_info: UserInfo = EventUserInfo()):
|
||||
return (
|
||||
user_info.user_displayname or user_info.user_remark or user_info.user_name
|
||||
) or ""
|
||||
async def dependency(user_info: Uninfo):
|
||||
return user_info.user.nick or user_info.user.name or ""
|
||||
|
||||
return Depends(dependency)
|
||||
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
import os
|
||||
import random
|
||||
|
||||
from nonebot_plugin_htmlrender import template_to_pic
|
||||
|
||||
from zhenxun.configs.path_config import TEMPLATE_PATH
|
||||
from zhenxun.utils._build_image import BuildImage
|
||||
from zhenxun.configs.path_config import TEMPLATE_PATH
|
||||
|
||||
from .models import Barh
|
||||
|
||||
BACKGROUND_PATH = TEMPLATE_PATH / "bar_chart" / "background"
|
||||
|
||||
|
||||
class ChartUtils:
|
||||
|
||||
@classmethod
|
||||
async def barh(cls, data: Barh) -> BuildImage:
|
||||
"""横向统计图"""
|
||||
to_json = data.dict()
|
||||
to_json["background_image"] = (
|
||||
f"./background/{random.choice(os.listdir(BACKGROUND_PATH))}"
|
||||
)
|
||||
pic = await template_to_pic(
|
||||
template_path=str((TEMPLATE_PATH / "bar_chart").absolute()),
|
||||
template_name="main.html",
|
||||
templates={"data": data},
|
||||
templates={"data": to_json},
|
||||
pages={
|
||||
"viewport": {"width": 1000, "height": 500},
|
||||
"viewport": {"width": 1000, "height": 1000},
|
||||
"base_url": f"file://{TEMPLATE_PATH}",
|
||||
},
|
||||
wait=2,
|
||||
|
||||
@@ -2,8 +2,9 @@ from pydantic import BaseModel
|
||||
|
||||
|
||||
class Barh(BaseModel):
|
||||
|
||||
category_data: list[str]
|
||||
"""坐标轴数据"""
|
||||
data: list[int | float]
|
||||
"""实际数据"""
|
||||
title: str
|
||||
"""标题"""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from collections.abc import Generator
|
||||
|
||||
from .consts import GITHUB_REPO_URL_PATTERN
|
||||
from .const import GITHUB_REPO_URL_PATTERN
|
||||
from .func import get_fastest_raw_formats, get_fastest_archive_formats
|
||||
from .models import RepoAPI, RepoInfo, GitHubStrategy, JsdelivrStrategy
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import re
|
||||
|
||||
GITHUB_REPO_URL_PATTERN = re.compile(
|
||||
r"^https://github.com/(?P<owner>[^/]+)/(?P<repo>[^/]+)(/tree/(?P<branch>[^/]+))?$"
|
||||
)
|
||||
"""github仓库地址正则"""
|
||||
|
||||
JSD_PACKAGE_API_FORMAT = (
|
||||
"https://data.jsdelivr.com/v1/packages/gh/{owner}/{repo}@{branch}"
|
||||
)
|
||||
"""jsdelivr包地址格式"""
|
||||
|
||||
GIT_API_TREES_FORMAT = (
|
||||
"https://api.github.com/repos/{owner}/{repo}/git/trees/{branch}?recursive=1"
|
||||
)
|
||||
"""git api trees地址格式"""
|
||||
|
||||
CACHED_API_TTL = 300
|
||||
"""缓存api ttl"""
|
||||
|
||||
RAW_CONTENT_FORMAT = "https://raw.githubusercontent.com/{owner}/{repo}/{branch}/{path}"
|
||||
"""raw content格式"""
|
||||
|
||||
ARCHIVE_URL_FORMAT = "https://github.com/{owner}/{repo}/archive/refs/heads/{branch}.zip"
|
||||
"""archive url格式"""
|
||||
|
||||
RELEASE_ASSETS_FORMAT = (
|
||||
"https://github.com/{owner}/{repo}/releases/download/{version}/{filename}"
|
||||
)
|
||||
"""release assets格式"""
|
||||
|
||||
RELEASE_SOURCE_FORMAT = (
|
||||
"https://codeload.github.com/{owner}/{repo}/legacy.{compress}/refs/tags/{version}"
|
||||
)
|
||||
"""release 源码格式"""
|
||||
@@ -1,7 +1,7 @@
|
||||
from aiocache import cached
|
||||
|
||||
from ..http_utils import AsyncHttpx
|
||||
from .consts import (
|
||||
from .const import (
|
||||
ARCHIVE_URL_FORMAT,
|
||||
RAW_CONTENT_FORMAT,
|
||||
RELEASE_ASSETS_FORMAT,
|
||||
|
||||
@@ -5,7 +5,7 @@ from strenum import StrEnum
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ..http_utils import AsyncHttpx
|
||||
from .consts import CACHED_API_TTL, GIT_API_TREES_FORMAT, JSD_PACKAGE_API_FORMAT
|
||||
from .const import CACHED_API_TTL, GIT_API_TREES_FORMAT, JSD_PACKAGE_API_FORMAT
|
||||
from .func import (
|
||||
get_fastest_raw_formats,
|
||||
get_fastest_archive_formats,
|
||||
@@ -199,13 +199,15 @@ class GitHubStrategy:
|
||||
|
||||
body: TreeInfo
|
||||
|
||||
def export_files(self, module_path: str) -> list[str]:
|
||||
def export_files(self, module_path: str, is_dir: bool) -> list[str]:
|
||||
"""导出文件路径"""
|
||||
tree_info = self.body
|
||||
return [
|
||||
file.path
|
||||
for file in tree_info.tree
|
||||
if file.type == TreeType.FILE and file.path.startswith(module_path)
|
||||
if file.type == TreeType.FILE
|
||||
and file.path.startswith(module_path)
|
||||
and (not is_dir or file.path[len(module_path)] == "/")
|
||||
]
|
||||
|
||||
@classmethod
|
||||
@@ -229,4 +231,4 @@ class GitHubStrategy:
|
||||
|
||||
def get_files(self, module_path: str, is_dir: bool = True) -> list[str]:
|
||||
"""获取文件路径"""
|
||||
return self.export_files(module_path)
|
||||
return self.export_files(module_path, is_dir)
|
||||
|
||||
+13
-15
@@ -101,7 +101,7 @@ class AsyncHttpx:
|
||||
) -> Response:
|
||||
if not headers:
|
||||
headers = get_user_agent()
|
||||
_proxy = proxy if proxy else cls.proxy if use_proxy else None
|
||||
_proxy = proxy or (cls.proxy if use_proxy else None)
|
||||
async with httpx.AsyncClient(proxies=_proxy, verify=verify) as client: # type: ignore
|
||||
return await client.get(
|
||||
url,
|
||||
@@ -140,7 +140,7 @@ class AsyncHttpx:
|
||||
"""
|
||||
if not headers:
|
||||
headers = get_user_agent()
|
||||
_proxy = proxy if proxy else cls.proxy if use_proxy else None
|
||||
_proxy = proxy or (cls.proxy if use_proxy else None)
|
||||
async with httpx.AsyncClient(proxies=_proxy, verify=verify) as client: # type: ignore
|
||||
return await client.head(
|
||||
url,
|
||||
@@ -187,7 +187,7 @@ class AsyncHttpx:
|
||||
"""
|
||||
if not headers:
|
||||
headers = get_user_agent()
|
||||
_proxy = proxy if proxy else cls.proxy if use_proxy else None
|
||||
_proxy = proxy or (cls.proxy if use_proxy else None)
|
||||
async with httpx.AsyncClient(proxies=_proxy, verify=verify) as client: # type: ignore
|
||||
return await client.post(
|
||||
url,
|
||||
@@ -202,6 +202,11 @@ class AsyncHttpx:
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_content(cls, url: str, **kwargs) -> bytes | None:
|
||||
res = await cls.get(url, **kwargs)
|
||||
return res.content if res and res.status_code == 200 else None
|
||||
|
||||
@classmethod
|
||||
async def download_file(
|
||||
cls,
|
||||
@@ -259,13 +264,10 @@ class AsyncHttpx:
|
||||
async with aiofiles.open(path, "wb") as wf:
|
||||
await wf.write(content)
|
||||
logger.info(f"下载 {u} 成功.. Path:{path.absolute()}")
|
||||
return True
|
||||
else:
|
||||
if not headers:
|
||||
headers = get_user_agent()
|
||||
_proxy = (
|
||||
proxy if proxy else cls.proxy if use_proxy else None
|
||||
)
|
||||
_proxy = proxy or (cls.proxy if use_proxy else None)
|
||||
async with httpx.AsyncClient(
|
||||
proxies=_proxy, # type: ignore
|
||||
verify=verify,
|
||||
@@ -298,7 +300,7 @@ class AsyncHttpx:
|
||||
) as progress:
|
||||
download_task = progress.add_task(
|
||||
"Download",
|
||||
total=total if total else None,
|
||||
total=total or None,
|
||||
)
|
||||
async for chunk in response.aiter_bytes():
|
||||
await wf.write(chunk)
|
||||
@@ -311,11 +313,10 @@ class AsyncHttpx:
|
||||
f"下载 {u} 成功.. "
|
||||
f"Path:{path.absolute()}"
|
||||
)
|
||||
return True
|
||||
return True
|
||||
except (TimeoutError, ConnectTimeout, HTTPStatusError):
|
||||
logger.warning(f"下载 {u} 失败.. 尝试下一个地址..")
|
||||
else:
|
||||
logger.error(f"下载 {url} 下载超时.. Path:{path.absolute()}")
|
||||
logger.error(f"下载 {url} 下载超时.. Path:{path.absolute()}")
|
||||
except Exception as e:
|
||||
logger.error(f"下载 {url} 错误 Path:{path.absolute()}", e=e)
|
||||
return False
|
||||
@@ -479,10 +480,7 @@ class AsyncPlaywright:
|
||||
if isinstance(path, str):
|
||||
path = Path(path)
|
||||
wait_time = wait_time * 1000 if wait_time else None
|
||||
if isinstance(element, str):
|
||||
element_list = [element]
|
||||
else:
|
||||
element_list = element
|
||||
element_list = [element] if isinstance(element, str) else element
|
||||
async with cls.new_page(
|
||||
viewport=viewport_size,
|
||||
user_agent=user_agent,
|
||||
|
||||
+61
-29
@@ -7,20 +7,24 @@ import nonebot
|
||||
from pydantic import BaseModel
|
||||
from nonebot.adapters import Bot
|
||||
from nonebot.utils import is_coroutine_callable
|
||||
from nonebot_plugin_alconna import SupportScope
|
||||
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_plugin_uninfo import Uninfo, get_interface
|
||||
from nonebot.adapters.kaiheila import Bot as KaiheilaBot
|
||||
from nonebot_plugin_alconna.uniseg import Target, Receipt, UniMessage
|
||||
|
||||
from zhenxun.services.log import logger
|
||||
from zhenxun.configs.config import BotConfig
|
||||
from zhenxun.utils.message import MessageUtils
|
||||
from zhenxun.utils.http_utils import AsyncHttpx
|
||||
from zhenxun.models.friend_user import FriendUser
|
||||
from zhenxun.utils.exception import NotFindSuperuser
|
||||
from zhenxun.models.group_console import GroupConsole
|
||||
|
||||
driver = nonebot.get_driver()
|
||||
|
||||
|
||||
class UserData(BaseModel):
|
||||
name: str
|
||||
@@ -40,6 +44,20 @@ class UserData(BaseModel):
|
||||
|
||||
|
||||
class PlatformUtils:
|
||||
@classmethod
|
||||
def is_qbot(cls, session: Uninfo | Bot) -> bool:
|
||||
"""判断bot是否为qq官bot
|
||||
|
||||
参数:
|
||||
session: Uninfo
|
||||
|
||||
返回:
|
||||
bool: 是否为官bot
|
||||
"""
|
||||
if isinstance(session, Bot):
|
||||
return bool(BotConfig.get_qbot_uid(session.self_id))
|
||||
return session.scope == SupportScope.qq_api
|
||||
|
||||
@classmethod
|
||||
async def ban_user(cls, bot: Bot, user_id: str, group_id: str, duration: int):
|
||||
"""禁言
|
||||
@@ -244,30 +262,27 @@ class PlatformUtils:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
async def get_user_avatar(cls, user_id: str, platform: str) -> bytes | None:
|
||||
async def get_user_avatar(
|
||||
cls, user_id: str, platform: str, appid: str | None = None
|
||||
) -> bytes | None:
|
||||
"""快捷获取用户头像
|
||||
|
||||
参数:
|
||||
user_id: 用户id
|
||||
platform: 平台
|
||||
"""
|
||||
url = None
|
||||
if platform == "qq":
|
||||
url = f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=160"
|
||||
async with httpx.AsyncClient() as client:
|
||||
for _ in range(3):
|
||||
try:
|
||||
return (await client.get(url)).content
|
||||
except Exception:
|
||||
logger.error(
|
||||
"获取用户头像错误",
|
||||
"Util",
|
||||
target=user_id,
|
||||
platform=platform,
|
||||
)
|
||||
return None
|
||||
if user_id.isdigit():
|
||||
url = f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=160"
|
||||
else:
|
||||
url = f"https://q.qlogo.cn/qqapp/{appid}/{user_id}/100"
|
||||
return await AsyncHttpx.get_content(url) if url else None
|
||||
|
||||
@classmethod
|
||||
def get_user_avatar_url(cls, user_id: str, platform: str) -> str | None:
|
||||
def get_user_avatar_url(
|
||||
cls, user_id: str, platform: str, appid: str | None = None
|
||||
) -> str | None:
|
||||
"""快捷获取用户头像url
|
||||
|
||||
参数:
|
||||
@@ -275,8 +290,13 @@ class PlatformUtils:
|
||||
platform: 平台
|
||||
"""
|
||||
if platform == "qq":
|
||||
return f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=160"
|
||||
return None
|
||||
return (
|
||||
f"http://q1.qlogo.cn/g?b=qq&nk={user_id}&s=160"
|
||||
if user_id.isdigit()
|
||||
else f"https://q.qlogo.cn/qqapp/{appid}/{user_id}/100"
|
||||
)
|
||||
else:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
async def get_group_avatar(cls, gid: str, platform: str) -> bytes | None:
|
||||
@@ -371,7 +391,7 @@ class PlatformUtils:
|
||||
return len(create_list)
|
||||
|
||||
@classmethod
|
||||
def get_platform(cls, bot: Bot) -> str | None:
|
||||
def get_platform(cls, t: Bot | Uninfo) -> str:
|
||||
"""获取平台
|
||||
|
||||
参数:
|
||||
@@ -380,13 +400,15 @@ 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 isinstance(t, Bot):
|
||||
if interface := get_interface(t):
|
||||
info = interface.basic_info()
|
||||
platform = info["scope"].lower()
|
||||
return "qq" if platform.startswith("qq") else platform
|
||||
else:
|
||||
platform = t.basic["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]:
|
||||
@@ -550,7 +572,7 @@ async def broadcast_group(
|
||||
bot: Bot | list[Bot] | None = None,
|
||||
bot_id: str | set[str] | None = None,
|
||||
ignore_group: set[int] | None = None,
|
||||
check_func: Callable[[str], Awaitable] | None = None,
|
||||
check_func: Callable[[Bot, str], Awaitable] | None = None,
|
||||
log_cmd: str | None = None,
|
||||
platform: Literal["qq", "dodo", "kaiheila"] | None = None,
|
||||
):
|
||||
@@ -604,14 +626,24 @@ async def broadcast_group(
|
||||
or group.channel_id in ignore_group
|
||||
)
|
||||
) or key in _used_group:
|
||||
logger.debug(
|
||||
"广播方法群组重复, 已跳过...",
|
||||
log_cmd,
|
||||
group_id=group.group_id,
|
||||
)
|
||||
continue
|
||||
is_run = False
|
||||
if check_func:
|
||||
if is_coroutine_callable(check_func):
|
||||
is_run = await check_func(group.group_id)
|
||||
is_run = await check_func(_bot, group.group_id)
|
||||
else:
|
||||
is_run = check_func(group.group_id)
|
||||
is_run = check_func(_bot, group.group_id)
|
||||
if not is_run:
|
||||
logger.debug(
|
||||
"广播方法检测运行方法为 False, 已跳过...",
|
||||
log_cmd,
|
||||
group_id=group.group_id,
|
||||
)
|
||||
continue
|
||||
target = PlatformUtils.get_target(
|
||||
_bot, None, group.group_id, group.channel_id
|
||||
|
||||
@@ -2,7 +2,6 @@ from pydantic import BaseModel
|
||||
|
||||
|
||||
class CommonSql(BaseModel):
|
||||
|
||||
sql: str
|
||||
"""sql语句"""
|
||||
remark: str
|
||||
|
||||
+39
-9
@@ -1,10 +1,12 @@
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.internal.rule import Rule
|
||||
from nonebot.adapters import Bot, Event
|
||||
from nonebot.permission import SUPERUSER
|
||||
from nonebot_plugin_session import EventSession, SessionLevel
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
from nonebot_plugin_session import EventSession
|
||||
|
||||
from zhenxun.configs.config import Config
|
||||
from zhenxun.models.level_user import LevelUser
|
||||
from zhenxun.utils.platform import PlatformUtils
|
||||
|
||||
|
||||
def admin_check(a: int | str, key: str | None = None) -> Rule:
|
||||
@@ -19,33 +21,38 @@ def admin_check(a: int | str, key: str | None = None) -> Rule:
|
||||
Rule: Rule
|
||||
"""
|
||||
|
||||
async def _rule(bot: Bot, event: Event, session: EventSession) -> bool:
|
||||
async def _rule(bot: Bot, event: Event, session: Uninfo) -> bool:
|
||||
if await SUPERUSER(bot, event):
|
||||
return True
|
||||
if session.id1 and session.id2:
|
||||
if PlatformUtils.is_qbot(session):
|
||||
"""官bot接口,放弃所有权限检查"""
|
||||
return False
|
||||
if session.id and session.group:
|
||||
level = a
|
||||
if type(a) == str and key:
|
||||
if isinstance(a, str) and key:
|
||||
level = Config.get_config(a, key)
|
||||
if level is not None:
|
||||
return bool(
|
||||
await LevelUser.check_level(session.id1, session.id2, int(level))
|
||||
await LevelUser.check_level(
|
||||
session.id, session.group.id, int(level)
|
||||
)
|
||||
)
|
||||
return False
|
||||
|
||||
return Rule(_rule)
|
||||
|
||||
|
||||
def ensure_group(session: EventSession) -> bool:
|
||||
def ensure_group(session: Uninfo) -> bool:
|
||||
"""
|
||||
是否在群聊中
|
||||
|
||||
参数:
|
||||
session: session
|
||||
session: Uninfo
|
||||
|
||||
返回:
|
||||
bool: bool
|
||||
"""
|
||||
return session.level in [SessionLevel.LEVEL2, SessionLevel.LEVEL3]
|
||||
return bool(session.group)
|
||||
|
||||
|
||||
def ensure_private(session: EventSession) -> bool:
|
||||
@@ -59,3 +66,26 @@ def ensure_private(session: EventSession) -> bool:
|
||||
bool: bool
|
||||
"""
|
||||
return not session.id3 and not session.id2
|
||||
|
||||
|
||||
def notice_rule(event_type: type | list[type]) -> Rule:
|
||||
"""
|
||||
Notice限制
|
||||
|
||||
参数:
|
||||
event_type: Event类型
|
||||
|
||||
返回:
|
||||
Rule: Rule
|
||||
"""
|
||||
|
||||
async def _rule(event: Event) -> bool:
|
||||
if isinstance(event_type, list):
|
||||
for et in event_type:
|
||||
if isinstance(event, et):
|
||||
return True
|
||||
else:
|
||||
return isinstance(event, event_type)
|
||||
return False
|
||||
|
||||
return Rule(_rule)
|
||||
|
||||
Reference in New Issue
Block a user