mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2025-12-15 06:12:53 +08:00
⚡️ 优化权限判断
This commit is contained in:
parent
369451c4a5
commit
862c977eda
@ -220,7 +220,9 @@ async def _(
|
|||||||
await MessageUtils.build_message("权限不足捏...").finish(reply_to=True)
|
await MessageUtils.build_message("权限不足捏...").finish(reply_to=True)
|
||||||
user_id = user.result
|
user_id = user.result
|
||||||
if gid := session.id3 or session.id2:
|
if gid := session.id3 or session.id2:
|
||||||
|
u_d = user_id
|
||||||
if group_id.available:
|
if group_id.available:
|
||||||
|
u_d = gid
|
||||||
gid = group_id.result
|
gid = group_id.result
|
||||||
if await BanManage.unban(
|
if await BanManage.unban(
|
||||||
user_id, gid, session, session.id1 in bot.config.superusers
|
user_id, gid, session, session.id1 in bot.config.superusers
|
||||||
@ -234,7 +236,7 @@ async def _(
|
|||||||
await MessageUtils.build_message(
|
await MessageUtils.build_message(
|
||||||
[
|
[
|
||||||
"将 ",
|
"将 ",
|
||||||
At(flag="user", target=user_id) if isinstance(user.result, At) else user_id, # type: ignore
|
At(flag="user", target=user_id) if isinstance(user.result, At) else u_d, # type: ignore
|
||||||
f" 从黑屋中拉了出来并急救了一下!",
|
f" 从黑屋中拉了出来并急救了一下!",
|
||||||
]
|
]
|
||||||
).finish(reply_to=True)
|
).finish(reply_to=True)
|
||||||
|
|||||||
@ -30,7 +30,7 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
extra=PluginExtraData(
|
extra=PluginExtraData(
|
||||||
author="HibiKier",
|
author="HibiKier",
|
||||||
version="0.1",
|
version="0.1",
|
||||||
plugin_type=PluginType.HIDDEN,
|
plugin_type=PluginType.DEPENDANT,
|
||||||
configs=[
|
configs=[
|
||||||
RegisterConfig(
|
RegisterConfig(
|
||||||
key="type",
|
key="type",
|
||||||
|
|||||||
@ -49,7 +49,7 @@ class HelpImageBuild:
|
|||||||
self._data = await PluginInfo.filter(
|
self._data = await PluginInfo.filter(
|
||||||
menu_type__not="",
|
menu_type__not="",
|
||||||
load_status=True,
|
load_status=True,
|
||||||
plugin_type__in=[PluginType.NORMAL, PluginType.HIDDEN],
|
plugin_type__in=[PluginType.NORMAL, PluginType.DEPENDANT],
|
||||||
)
|
)
|
||||||
if not self._sort_data:
|
if not self._sort_data:
|
||||||
for plugin in self._data:
|
for plugin in self._data:
|
||||||
|
|||||||
@ -24,7 +24,7 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
extra=PluginExtraData(
|
extra=PluginExtraData(
|
||||||
author="HibiKier",
|
author="HibiKier",
|
||||||
version="0.1",
|
version="0.1",
|
||||||
plugin_type=PluginType.HIDDEN,
|
plugin_type=PluginType.DEPENDANT,
|
||||||
).dict(),
|
).dict(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -40,4 +40,13 @@ Config.add_plugin_config(
|
|||||||
type=int,
|
type=int,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Config.add_plugin_config(
|
||||||
|
"hook",
|
||||||
|
"IS_SEND_TIP_MESSAGE",
|
||||||
|
True,
|
||||||
|
help="是否发送阻断时提示消息",
|
||||||
|
default_value=True,
|
||||||
|
type=bool,
|
||||||
|
)
|
||||||
|
|
||||||
nonebot.load_plugins(str(Path(__file__).parent.resolve()))
|
nonebot.load_plugins(str(Path(__file__).parent.resolve()))
|
||||||
|
|||||||
@ -25,6 +25,8 @@ from zhenxun.utils.exception import InsufficientGold
|
|||||||
from zhenxun.utils.message import MessageUtils
|
from zhenxun.utils.message import MessageUtils
|
||||||
from zhenxun.utils.utils import CountLimiter, FreqLimiter, UserBlockLimiter
|
from zhenxun.utils.utils import CountLimiter, FreqLimiter, UserBlockLimiter
|
||||||
|
|
||||||
|
base_config = Config.get("hook")
|
||||||
|
|
||||||
|
|
||||||
class Limit(BaseModel):
|
class Limit(BaseModel):
|
||||||
|
|
||||||
@ -181,6 +183,23 @@ class AuthChecker:
|
|||||||
self._flmt_s = FreqLimiter(check_notice_info_cd)
|
self._flmt_s = FreqLimiter(check_notice_info_cd)
|
||||||
self._flmt_c = FreqLimiter(check_notice_info_cd)
|
self._flmt_c = FreqLimiter(check_notice_info_cd)
|
||||||
|
|
||||||
|
def is_send_limit_message(self, plugin: PluginInfo, sid: str) -> bool:
|
||||||
|
"""是否发送提示消息
|
||||||
|
|
||||||
|
参数:
|
||||||
|
plugin: PluginInfo
|
||||||
|
|
||||||
|
返回:
|
||||||
|
bool: 是否发送提示消息
|
||||||
|
"""
|
||||||
|
if not base_config.get("IS_SEND_TIP_MESSAGE"):
|
||||||
|
return False
|
||||||
|
if plugin.plugin_type == PluginType.DEPENDANT:
|
||||||
|
return False
|
||||||
|
if not self._flmt_s.check(sid):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
async def auth(
|
async def auth(
|
||||||
self,
|
self,
|
||||||
matcher: Matcher,
|
matcher: Matcher,
|
||||||
@ -217,8 +236,8 @@ class AuthChecker:
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
if plugin := await PluginInfo.get_or_none(module_path=module_path):
|
if plugin := await PluginInfo.get_or_none(module_path=module_path):
|
||||||
if plugin.plugin_type == PluginType.HIDDEN and plugin.name != "帮助":
|
if plugin.plugin_type == PluginType.HIDDEN:
|
||||||
logger.debug("插件为HIDDEN且不是帮助功能,已跳过...")
|
logger.debug("插件为HIDDEN,已跳过...")
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
cost_gold = await self.auth_cost(user, plugin, session)
|
cost_gold = await self.auth_cost(user, plugin, session)
|
||||||
@ -301,11 +320,12 @@ class AuthChecker:
|
|||||||
channel_id = None
|
channel_id = None
|
||||||
if user_id:
|
if user_id:
|
||||||
if group_id:
|
if group_id:
|
||||||
|
sid = group_id or user_id
|
||||||
if await GroupConsole.is_super_block_plugin(
|
if await GroupConsole.is_super_block_plugin(
|
||||||
group_id, plugin.module, channel_id
|
group_id, plugin.module, channel_id
|
||||||
):
|
):
|
||||||
"""超级用户群组插件状态"""
|
"""超级用户群组插件状态"""
|
||||||
if self._flmt_s.check(group_id or user_id) and not is_poke:
|
if self.is_send_limit_message(plugin, sid) and not is_poke:
|
||||||
self._flmt_s.start_cd(group_id or user_id)
|
self._flmt_s.start_cd(group_id or user_id)
|
||||||
await MessageUtils.build_message(
|
await MessageUtils.build_message(
|
||||||
"超级管理员禁用了该群此功能..."
|
"超级管理员禁用了该群此功能..."
|
||||||
@ -320,7 +340,7 @@ class AuthChecker:
|
|||||||
group_id, plugin.module, channel_id
|
group_id, plugin.module, channel_id
|
||||||
):
|
):
|
||||||
"""群组插件状态"""
|
"""群组插件状态"""
|
||||||
if self._flmt_s.check(group_id or user_id) and not is_poke:
|
if self.is_send_limit_message(plugin, sid) and not is_poke:
|
||||||
self._flmt_s.start_cd(group_id or user_id)
|
self._flmt_s.start_cd(group_id or user_id)
|
||||||
await MessageUtils.build_message("该群未开启此功能...").send(
|
await MessageUtils.build_message("该群未开启此功能...").send(
|
||||||
reply_to=True
|
reply_to=True
|
||||||
@ -334,7 +354,7 @@ class AuthChecker:
|
|||||||
if not plugin.status and plugin.block_type == BlockType.GROUP:
|
if not plugin.status and plugin.block_type == BlockType.GROUP:
|
||||||
"""全局群组禁用"""
|
"""全局群组禁用"""
|
||||||
try:
|
try:
|
||||||
if self._flmt_c.check(group_id) and not is_poke:
|
if self.is_send_limit_message(plugin, sid) and not is_poke:
|
||||||
self._flmt_c.start_cd(group_id)
|
self._flmt_c.start_cd(group_id)
|
||||||
await MessageUtils.build_message(
|
await MessageUtils.build_message(
|
||||||
"该功能在群组中已被禁用..."
|
"该功能在群组中已被禁用..."
|
||||||
@ -350,10 +370,11 @@ class AuthChecker:
|
|||||||
)
|
)
|
||||||
raise IgnoredException("该插件在群组中已被禁用...")
|
raise IgnoredException("该插件在群组中已被禁用...")
|
||||||
else:
|
else:
|
||||||
|
sid = user_id
|
||||||
if not plugin.status and plugin.block_type == BlockType.PRIVATE:
|
if not plugin.status and plugin.block_type == BlockType.PRIVATE:
|
||||||
"""全局私聊禁用"""
|
"""全局私聊禁用"""
|
||||||
try:
|
try:
|
||||||
if self._flmt_c.check(user_id) and not is_poke:
|
if self.is_send_limit_message(plugin, sid) and not is_poke:
|
||||||
self._flmt_c.start_cd(user_id)
|
self._flmt_c.start_cd(user_id)
|
||||||
await MessageUtils.build_message(
|
await MessageUtils.build_message(
|
||||||
"该功能在私聊中已被禁用..."
|
"该功能在私聊中已被禁用..."
|
||||||
@ -378,7 +399,7 @@ class AuthChecker:
|
|||||||
"HOOK",
|
"HOOK",
|
||||||
session=session,
|
session=session,
|
||||||
)
|
)
|
||||||
if self._flmt_s.check(group_id or user_id) and not is_poke:
|
if self.is_send_limit_message(plugin, sid) and not is_poke:
|
||||||
self._flmt_s.start_cd(group_id or user_id)
|
self._flmt_s.start_cd(group_id or user_id)
|
||||||
await MessageUtils.build_message("全局未开启此功能...").send()
|
await MessageUtils.build_message("全局未开启此功能...").send()
|
||||||
raise IgnoredException("全局未开启此功能...")
|
raise IgnoredException("全局未开启此功能...")
|
||||||
|
|||||||
@ -69,7 +69,7 @@ async def _(matcher: Matcher, bot: Bot, session: EventSession, state: T_State):
|
|||||||
module = plugin.module_name
|
module = plugin.module_name
|
||||||
if metadata := plugin.metadata:
|
if metadata := plugin.metadata:
|
||||||
extra = metadata.extra
|
extra = metadata.extra
|
||||||
if extra.get("plugin_type") == PluginType.HIDDEN:
|
if extra.get("plugin_type") in [PluginType.HIDDEN, PluginType.DEPENDANT]:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|||||||
@ -49,8 +49,9 @@ async def _handle_setting(
|
|||||||
if metadata.type == "library":
|
if metadata.type == "library":
|
||||||
extra_data.plugin_type = PluginType.HIDDEN
|
extra_data.plugin_type = PluginType.HIDDEN
|
||||||
if (
|
if (
|
||||||
extra_data.plugin_type == PluginType.HIDDEN
|
extra_data.plugin_type
|
||||||
and extra_data.plugin_type != "功能"
|
== PluginType.HIDDEN
|
||||||
|
# and extra_data.plugin_type != "功能"
|
||||||
):
|
):
|
||||||
extra_data.menu_type = ""
|
extra_data.menu_type = ""
|
||||||
plugin_list.append(
|
plugin_list.append(
|
||||||
@ -119,15 +120,26 @@ async def _():
|
|||||||
create_list.append(plugin)
|
create_list.append(plugin)
|
||||||
else:
|
else:
|
||||||
plugin.id = module2id[plugin.module_path]
|
plugin.id = module2id[plugin.module_path]
|
||||||
|
await plugin.save(
|
||||||
|
update_fields=[
|
||||||
|
"name",
|
||||||
|
"author",
|
||||||
|
"version",
|
||||||
|
"admin_level",
|
||||||
|
"plugin_type",
|
||||||
|
]
|
||||||
|
)
|
||||||
update_list.append(plugin)
|
update_list.append(plugin)
|
||||||
if create_list:
|
if create_list:
|
||||||
await PluginInfo.bulk_create(create_list, 10)
|
await PluginInfo.bulk_create(create_list, 10)
|
||||||
if update_list:
|
if update_list:
|
||||||
await PluginInfo.bulk_update(
|
# TODO: 批量更新无法更新plugin_type: tortoise.exceptions.OperationalError: column "superuser" does not exist
|
||||||
update_list,
|
pass
|
||||||
["name", "author", "version", "admin_level"],
|
# await PluginInfo.bulk_update(
|
||||||
10,
|
# update_list,
|
||||||
)
|
# ["name", "author", "version", "admin_level", "plugin_type"],
|
||||||
|
# 10,
|
||||||
|
# )
|
||||||
if limit_list:
|
if limit_list:
|
||||||
limit_create = []
|
limit_create = []
|
||||||
plugins = []
|
plugins = []
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
from asyncio.exceptions import TimeoutError
|
from asyncio.exceptions import TimeoutError
|
||||||
|
|
||||||
import nonebot
|
import nonebot
|
||||||
|
import ujson as json
|
||||||
from nonebot.drivers import Driver
|
from nonebot.drivers import Driver
|
||||||
from nonebot_plugin_apscheduler import scheduler
|
from nonebot_plugin_apscheduler import scheduler
|
||||||
|
|
||||||
@ -8,12 +9,6 @@ from zhenxun.configs.path_config import TEXT_PATH
|
|||||||
from zhenxun.services.log import logger
|
from zhenxun.services.log import logger
|
||||||
from zhenxun.utils.http_utils import AsyncHttpx
|
from zhenxun.utils.http_utils import AsyncHttpx
|
||||||
|
|
||||||
try:
|
|
||||||
import ujson as json
|
|
||||||
except ModuleNotFoundError:
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
|
||||||
driver: Driver = nonebot.get_driver()
|
driver: Driver = nonebot.get_driver()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ from zhenxun.services.log import logger
|
|||||||
from zhenxun.utils.message import MessageUtils
|
from zhenxun.utils.message import MessageUtils
|
||||||
|
|
||||||
__plugin_meta__ = PluginMetadata(
|
__plugin_meta__ = PluginMetadata(
|
||||||
name="识番",
|
name="关于",
|
||||||
description="想要更加了解真寻吗",
|
description="想要更加了解真寻吗",
|
||||||
usage="""
|
usage="""
|
||||||
指令:
|
指令:
|
||||||
|
|||||||
@ -21,7 +21,8 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
extra=PluginExtraData(
|
extra=PluginExtraData(
|
||||||
author="HibiKier",
|
author="HibiKier",
|
||||||
version="0.1",
|
version="0.1",
|
||||||
plugin_type=PluginType.HIDDEN,
|
menu_type="其他",
|
||||||
|
plugin_type=PluginType.DEPENDANT,
|
||||||
).dict(),
|
).dict(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
author="HibiKier",
|
author="HibiKier",
|
||||||
version="0.1",
|
version="0.1",
|
||||||
menu_type="其他",
|
menu_type="其他",
|
||||||
plugin_type=PluginType.HIDDEN,
|
plugin_type=PluginType.DEPENDANT,
|
||||||
tasks=[Task(module="fudu", name="复读")],
|
tasks=[Task(module="fudu", name="复读")],
|
||||||
configs=[
|
configs=[
|
||||||
RegisterConfig(
|
RegisterConfig(
|
||||||
|
|||||||
@ -7,6 +7,7 @@ from nonebot_plugin_session import EventSession
|
|||||||
|
|
||||||
from zhenxun.configs.config import NICKNAME
|
from zhenxun.configs.config import NICKNAME
|
||||||
from zhenxun.configs.utils import PluginExtraData
|
from zhenxun.configs.utils import PluginExtraData
|
||||||
|
from zhenxun.models.ban_console import BanConsole
|
||||||
from zhenxun.services.log import logger
|
from zhenxun.services.log import logger
|
||||||
from zhenxun.utils.enum import PluginType
|
from zhenxun.utils.enum import PluginType
|
||||||
from zhenxun.utils.image_utils import get_download_image_hash
|
from zhenxun.utils.image_utils import get_download_image_hash
|
||||||
@ -23,7 +24,7 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
author="HibiKier",
|
author="HibiKier",
|
||||||
version="0.1",
|
version="0.1",
|
||||||
menu_type="其他",
|
menu_type="其他",
|
||||||
plugin_type=PluginType.HIDDEN,
|
plugin_type=PluginType.DEPENDANT,
|
||||||
).dict(),
|
).dict(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -35,6 +36,8 @@ async def _(bot: Bot, session: EventSession, message: UniMsg):
|
|||||||
group_id = session.id2
|
group_id = session.id2
|
||||||
if not session.id1 or not group_id:
|
if not session.id1 or not group_id:
|
||||||
return
|
return
|
||||||
|
if await BanConsole.is_ban(session.id1, group_id):
|
||||||
|
return
|
||||||
plain_text = message.extract_plain_text()
|
plain_text = message.extract_plain_text()
|
||||||
image_list = [m.url for m in message if isinstance(m, alcImage) and m.url]
|
image_list = [m.url for m in message if isinstance(m, alcImage) and m.url]
|
||||||
img_hash = ""
|
img_hash = ""
|
||||||
|
|||||||
@ -28,7 +28,8 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
extra=PluginExtraData(
|
extra=PluginExtraData(
|
||||||
author="leekooyo",
|
author="leekooyo",
|
||||||
version="0.1",
|
version="0.1",
|
||||||
plugin_type=PluginType.HIDDEN,
|
plugin_type=PluginType.DEPENDANT,
|
||||||
|
menu_type="其他",
|
||||||
configs=[
|
configs=[
|
||||||
RegisterConfig(
|
RegisterConfig(
|
||||||
module="_task",
|
module="_task",
|
||||||
|
|||||||
@ -24,7 +24,7 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
author="HibiKier",
|
author="HibiKier",
|
||||||
version="0.1",
|
version="0.1",
|
||||||
menu_type="其他",
|
menu_type="其他",
|
||||||
plugin_type=PluginType.HIDDEN,
|
plugin_type=PluginType.DEPENDANT,
|
||||||
).dict(),
|
).dict(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -72,7 +72,7 @@ async def _() -> Result:
|
|||||||
load_status=True,
|
load_status=True,
|
||||||
).count()
|
).count()
|
||||||
plugin_count.other = await DbPluginInfo.filter(
|
plugin_count.other = await DbPluginInfo.filter(
|
||||||
plugin_type=PluginType.HIDDEN, load_status=True
|
plugin_type__in=[PluginType.HIDDEN, PluginType.DEPENDANT], load_status=True
|
||||||
).count()
|
).count()
|
||||||
return Result.ok(plugin_count)
|
return Result.ok(plugin_count)
|
||||||
|
|
||||||
|
|||||||
@ -226,7 +226,7 @@ class WordBankManage:
|
|||||||
problem, _problem_list = await WordBank.get_problem_all_answer(
|
problem, _problem_list = await WordBank.get_problem_all_answer(
|
||||||
problem, # type: ignore
|
problem, # type: ignore
|
||||||
index,
|
index,
|
||||||
group_id if group_id is None else None,
|
group_id if group_id is not None else None,
|
||||||
word_scope,
|
word_scope,
|
||||||
)
|
)
|
||||||
if not _problem_list:
|
if not _problem_list:
|
||||||
@ -248,7 +248,8 @@ class WordBankManage:
|
|||||||
# __text = (m.data["image"], 30, 30)
|
# __text = (m.data["image"], 30, 30)
|
||||||
__text = "[图片]"
|
__text = "[图片]"
|
||||||
_text.append(__text)
|
_text.append(__text)
|
||||||
msg_list.append("".join(str(_text)))
|
_text = "".join(_text)
|
||||||
|
msg_list.append(_text)
|
||||||
column_name = ["序号", "回答内容"]
|
column_name = ["序号", "回答内容"]
|
||||||
data_list = []
|
data_list = []
|
||||||
for index, msg in enumerate(msg_list):
|
for index, msg in enumerate(msg_list):
|
||||||
|
|||||||
@ -15,7 +15,7 @@ __plugin_meta__ = PluginMetadata(
|
|||||||
description="",
|
description="",
|
||||||
usage="""""",
|
usage="""""",
|
||||||
extra=PluginExtraData(
|
extra=PluginExtraData(
|
||||||
author="HibiKier", version="0.1", plugin_type=PluginType.HIDDEN
|
author="HibiKier", version="0.1", plugin_type=PluginType.DEPENDANT
|
||||||
).dict(),
|
).dict(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,4 +28,4 @@ async def _(session: EventSession, state: T_State):
|
|||||||
gid = session.id3 or session.id2
|
gid = session.id3 or session.id2
|
||||||
if result := await WordBank.get_answer(gid, problem):
|
if result := await WordBank.get_answer(gid, problem):
|
||||||
await result.send()
|
await result.send()
|
||||||
logger.info(f" 触发词条 {problem}", "词条检测", session=session)
|
logger.info(f"触发词条 {problem}", "词条检测", session=session)
|
||||||
|
|||||||
@ -322,4 +322,8 @@ async def _(
|
|||||||
None, index.result if index.available else None, group_id, word_scope
|
None, index.result if index.available else None, group_id, word_scope
|
||||||
)
|
)
|
||||||
await result.send()
|
await result.send()
|
||||||
logger.info(f"查看词条回答: {problem}", arparma.header_result, session=session)
|
logger.info(
|
||||||
|
f"查看词条回答: {problem.result if problem.available else index.result}",
|
||||||
|
arparma.header_result,
|
||||||
|
session=session,
|
||||||
|
)
|
||||||
|
|||||||
@ -31,10 +31,17 @@ class PluginType(StrEnum):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
SUPERUSER = "SUPERUSER"
|
SUPERUSER = "SUPERUSER"
|
||||||
|
"""超级用户"""
|
||||||
ADMIN = "ADMIN"
|
ADMIN = "ADMIN"
|
||||||
|
"""管理员"""
|
||||||
SUPER_AND_ADMIN = "ADMIN_SUPER"
|
SUPER_AND_ADMIN = "ADMIN_SUPER"
|
||||||
|
"""管理员以及超级用户"""
|
||||||
NORMAL = "NORMAL"
|
NORMAL = "NORMAL"
|
||||||
|
"""普通插件"""
|
||||||
|
DEPENDANT = "DEPENDANT"
|
||||||
|
"""依赖插件,一般为没有主动触发命令的插件,受权限控制"""
|
||||||
HIDDEN = "HIDDEN"
|
HIDDEN = "HIDDEN"
|
||||||
|
"""隐藏插件,一般为没有主动触发命令的插件,不受权限控制,如消息统计"""
|
||||||
|
|
||||||
|
|
||||||
class BlockType(StrEnum):
|
class BlockType(StrEnum):
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user