diff --git a/README.MD b/README.MD index d91db7f..1c1558c 100644 --- a/README.MD +++ b/README.MD @@ -371,12 +371,23 @@ async def _(bot: Bot, event: Event, matcher: Matcher): ```python @add_subject_extractor -def your_custom_subject_extractor(bot: Bot, event: Event, current: Sequence[str]) -> Sequence[str]: +def your_custom_subject_extractor(bot: Bot, event: Event, current: Sequence[SubjectModel]) -> Sequence[SubjectModel]: ... ``` 传入参数`bot`与`event`其义自明,而`current`参数表明当前阶段已经被提取出的主体,返回值表示经过该轮处理后提取出的主体。 +主体的模型定义如下: + +```python +class SubjectModel(NamedTuple): + content: str + offer_by: str + tag: Optional[str] +``` + +其中content为主体字符串,offer_by用于标识提取出该主体的主体提取器(通常为插件名),tag用于标识主体的种类。通常我们约定,拥有同一个tag的主体包含的信息量完全一致。 + 在主体提取流程,插件会**按顺序依次**调用已注册的主体提取器,每一轮调用时,将上一轮的返回值作为这一轮传入的`current` 参数,并取最后一轮的返回值作为事件的主体。请注意维护主体提取器注册的顺序。(tips:如果你的主体提取器依赖其他插件中实现的主体提取器,可以依赖`nonebot` 提供的`require`机制控制主体提取器注册的顺序) @@ -384,28 +395,41 @@ def your_custom_subject_extractor(bot: Bot, event: Event, current: Sequence[str] 例如,下面这个主体提取器用于为OneBot V11协议中群管理/群主提取相应的主体: ```python -def extract_onebot_v11_group_role(bot: Bot, event: Event, current: Sequence[str]) -> Sequence[str]: +OFFER_BY = "nonebot_plugin_access_control" + + +def extract_onebot_v11_group_role(bot: Bot, event: Event, current: Sequence[SubjectModel]) -> Sequence[SubjectModel]: if bot.type != "OneBot V11": return current - li = [*current] - group_id = getattr(event, "group_id", None) sender: Optional['Sender'] = getattr(event, "sender", None) if group_id is not None and sender is not None: - # 添加群管理/群主的subject(在"qq:g{group_id}"之前) - idx = li.index(f"qq:g{group_id}") + li = [] + if sender.role == 'owner': - li.insert(idx, f"qq:group_owner") - li.insert(idx, f"qq:g{group_id}.group_owner") + li.append(SubjectModel(f"qq:g{group_id}.group_owner", OFFER_BY, + f"qq:group.group_owner")) + li.append(SubjectModel(f"qq:group_owner", OFFER_BY, + f"qq:group_owner")) if sender.role == 'owner' or sender.role == 'admin': - li.insert(idx, f"qq:group_admin") - li.insert(idx, f"qq:g{group_id}.group_admin") + li.append(SubjectModel(f"qq:g{group_id}.group_admin", OFFER_BY, + f"qq:group.group_admin")) + li.append(SubjectModel(f"qq:group_admin", OFFER_BY, + f"qq:group_admin")) + + # 添加在platform:group之前 + idx = 0 + for i in range(len(current)): + if current[i].tag == "platform:group": + idx = i + break - return li + current = [*current[:idx], *li, *current[idx:]] + return current ``` ## CLI支持 diff --git a/docs/kaiheila.md b/docs/kaiheila.md index 7ce8755..6255c34 100644 --- a/docs/kaiheila.md +++ b/docs/kaiheila.md @@ -5,18 +5,20 @@ nonebot-plugin-access-control for Kaiheila 从上往下优先级从高到低 -| 主体 | 含义 | 示例 | 存在条件 | -|----------------------------------------------|---------|----------------------------------------|----------------------| -| kaiheila:g:c: | 服务器频道用户 | kaiheila:g87654321:c123454321:12345678 | 仅当消息来自频道时存在 | -| kaiheila:c: | 频道用户 | kaiheila:c123454321:12345678 | 仅当消息来自频道时存在 | -| kaiheila:g: | 服务器用户 | kaiheila:g87654321:12345678 | 仅当消息来自频道时存在 | -| kaiheila: | 用户 | kaiheila:12345678 | | -| superuser | 超级用户 | | 仅当该用户为超级用户时存在 | -| kaiheila:g.role_\ | 服务器角色 | kaiheila:g87654321.role_233 | 仅当消息来自频道、该用户拥有该身份时存在 | -| kaiheila:g:c | 服务器频道 | kaiheila:g87654321:c123454321 | 仅当消息来自频道时存在 | -| kaiheila:c | 频道 | kaiheila:c123454321 | 仅当消息来自频道时存在 | -| kaiheila:g | 服务器 | kaiheila:g87654321 | 仅当消息来自频道时存在 | -| kaiheila:private | 私聊消息 | | 仅当消息来自私聊时存在 | -| kaiheila:channel | 频道消息 | | 仅当消息来自频道时存在 | -| kaiheila | 某个平台用户 | | | -| all | 所有用户 | | | +| 主体 | TAG | 含义 | 示例 | 存在条件 | +|----------------------------------------------|-----------------------------|-----------------|----------------------------------------|----------------------| +| kaiheila:g:c: | platform:guild:channel:user | 服务器频道用户 | kaiheila:g87654321:c123454321:12345678 | 仅当消息来自频道时存在 | +| kaiheila:c: | platform:channel:user | 频道用户 | kaiheila:c123454321:12345678 | 仅当消息来自频道时存在 | +| kaiheila:g: | platform:guild:user | 服务器用户 | kaiheila:g87654321:12345678 | 仅当消息来自频道时存在 | +| kaiheila: | platform:user | 用户 | kaiheila:12345678 | | +| superuser | superuser | 超级用户 | | 仅当该用户为超级用户时存在 | +| kaiheila:g.role_\ | kaiheila:guild.role | 服务器角色 | kaiheila:g87654321.role_233 | 仅当消息来自频道、该用户拥有该身份时存在 | +| kaiheila:g:c | platform:guild:channel | 服务器频道 | kaiheila:g87654321:c123454321 | 仅当消息来自频道时存在 | +| kaiheila:c | platform:channel | 频道 | kaiheila:c123454321 | 仅当消息来自频道时存在 | +| kaiheila:g | platform:guild | 服务器 | kaiheila:g87654321 | 仅当消息来自频道时存在 | +| kaiheila:private | platform:private | 来自Kaiheila的私聊消息 | | 仅当消息来自私聊时存在 | +| private | private | 私聊消息 | | 仅当消息来自私聊时存在 | | | +| kaiheila:channel | platform:channel | 来自Kaiheila的频道消息 | | 仅当消息来自频道时存在 | +| channel | channel | 频道消息 | | 仅当消息来自频道是存在 | +| kaiheila | platform | 来自Kaiheila的用户 | | | +| all | all | 所有用户 | | | diff --git a/docs/onebot_v11.md b/docs/onebot_v11.md index 852e520..3c3e9ba 100644 --- a/docs/onebot_v11.md +++ b/docs/onebot_v11.md @@ -5,23 +5,25 @@ nonebot-plugin-access-control for OneBot V11 从上往下优先级从高到低 -| 主体 | 含义 | 示例 | 存在条件 | -|------------------------------|----------------|---------------------------|---------------| -| qq:g: | 群用户 | qq:g87654321:12345678 | 仅当消息来自群组时存在 | -| onebot:g: | 群用户(与上一条含义相同) | onebot:g87654321:12345678 | 仅当消息来自群组时存在 | -| qq: | 用户 | qq:12345678 | | -| onebot: | 用户(与上一条含义相同) | onebot:12345678 | | -| superuser | 超级用户 | | 仅当该用户为超级用户时存在 | -| qq:g | 群组 | qq:g87654321 | 仅当消息来自群组时存在 | -| onebot:g | 群组(与上一条含义相同) | onebot:g87654321 | 仅当消息来自群组时存在 | -| qq:g.group_owner | 群主 | qq.g87654321.group_owner | 仅当消息来自群组时存在 | -| qq:group_owner | 群主 | | 仅当消息来自群组时存在 | -| qq:g.group_admin | 群管理 | qq.g87654321.group_admin | 仅当消息来自群组时存在 | -| qq:group_admin | 群管理 | | 仅当消息来自群组时存在 | -| qq:private | 私聊消息 | | 仅当消息来自私聊时存在 | -| onebot:private | 私聊消息(与上一条含义相同) | | 仅当消息来自私聊时存在 | -| qq:group | 群聊消息 | | 仅当消息来自群聊时存在 | -| onebot:group | 群聊消息(与上一条含义相同) | | 仅当消息来自群聊时存在 | -| qq | QQ用户 | | | -| onebot | OneBot用户 | | | -| all | 所有用户 | | | +| 主体 | TAG | 含义 | 示例 | 存在条件 | +|------------------------------|----------------------|---------------|---------------------------|---------------| +| qq:g: | platform:group:user | 来自QQ的群用户 | qq:g87654321:12345678 | 仅当消息来自群组时存在 | +| onebot:g: | onebot:group:user | 来自OneBot的群用户 | onebot:g87654321:12345678 | 仅当消息来自群组时存在 | +| qq: | platform:user | 来自QQ的用户 | qq:12345678 | | +| onebot: | onebot:user | 来自OneBot的用户 | onebot:12345678 | | +| superuser | superuser | 超级用户 | | 仅当该用户为超级用户时存在 | +| qq:g.group_owner | qq:group.group_owner | 群主 | qq.g87654321.group_owner | 仅当消息来自群组时存在 | +| qq:group_owner | qq:group_owner | 群主 | | 仅当消息来自群组时存在 | +| qq:g.group_admin | qq:group.group_admin | 群管理 | qq.g87654321.group_admin | 仅当消息来自群组时存在 | +| qq:group_admin | qq:group_admin | 群管理 | | 仅当消息来自群组时存在 | +| qq:g | platform:group | 来自QQ的群组 | qq:g87654321 | 仅当消息来自群组时存在 | +| onebot:g | onebot:group | 来自OneBot的群组 | onebot:g87654321 | 仅当消息来自群组时存在 | +| qq:private | platform:chat_type | 来自QQ的私聊消息 | | 仅当消息来自私聊时存在 | +| onebot:private | onebot:chat_type | 来自OneBot的私聊消息 | | 仅当消息来自私聊时存在 | +| private | chat_type | 私聊消息 | | 仅当消息来自私聊时存在 | +| qq:group | platform:chat_type | 来自QQ的群聊消息 | | 仅当消息来自群聊时存在 | +| onebot:group | onebot:chat_type | 来自OneBot的群聊消息 | | 仅当消息来自群聊时存在 | +| group | group | 群聊消息 | | 仅当消息来自群聊时存在 | +| qq | platform | 来自QQ的用户 | | | +| onebot | onebot | 来自OneBot的用户 | | | +| all | all | 所有用户 | | | diff --git a/docs/onebot_v12.md b/docs/onebot_v12.md index cdf73f4..3beed93 100644 --- a/docs/onebot_v12.md +++ b/docs/onebot_v12.md @@ -5,48 +5,52 @@ nonebot-plugin-access-control for OneBot V12 从上往下优先级从高到低 -| 主体 | 含义 | 示例 | 存在条件 | -|-----------------------------------|----------------|---------------------------|----------------| -| \:g: | 群用户 | qq:g87654321:12345678 | | -| onebot:g: | 群用户 | onebot:g87654321:12345678 | | -| \: | 用户 | qq:12345678 | | -| onebot: | 用户 | onebot:12345678 | | -| superuser | 超级用户 | | 仅当该用户为超级用户时存在 | -| \:g | 群组 | qq:g87654321 | 仅当消息来自群组/频道时存在 | -| onebot:g | 群组 | onebot:g87654321 | 仅当消息来自群组/频道时存在 | -| \:private | 私聊消息 | qq:private | 仅当消息来自私聊时存在 | -| onebot:private | 私聊消息(与上一条含义相同) | | 仅当消息来自私聊时存在 | -| \:group | 群聊消息 | qq:group | 仅当消息来自群聊时存在 | -| onebot:group | 群聊消息(与上一条含义相同) | | 仅当消息来自群聊时存在 | -| \ | 某个平台用户 | qq | | -| onebot | OneBot用户 | | | -| all | 所有用户 | | | +| 主体 | TAG | 含义 | 示例 | 存在条件 | +|-----------------------------------|---------------------|--------------------|---------------------------|----------------| +| \:g: | platform:group:user | 来自\的群用户 | qq:g87654321:12345678 | 仅当消息来自群组时存在 | +| onebot:g: | onebot:group:user | 来自OneBot的群用户 | onebot:g87654321:12345678 | 仅当消息来自群组时存在 | +| \: | platform:user | 来自\的用户 | qq:12345678 | | +| onebot: | onebot:user | 来自OneBot的用户 | onebot:12345678 | | +| superuser | superuser | 超级用户 | | 仅当该用户为超级用户时存在 | +| \:g | platform:group | 来自\的群组 | qq:g87654321 | 仅当消息来自群组/频道时存在 | +| onebot:g | onebot:group | 来自OneBot的群组 | onebot:g87654321 | 仅当消息来自群组/频道时存在 | +| \:private | platform:chat_type | 来自\的私聊消息 | qq:private | 仅当消息来自私聊时存在 | +| onebot:private | onebot:chat_type | 来自OneBot的私聊消息 | | 仅当消息来自私聊时存在 | +| private | chat_type | 私聊消息 | 仅当消息来自私聊时存在 | | | | | | +| \:group | platform:chat_type | 来自\的群聊消息 | qq:group | 仅当消息来自群聊时存在 | +| onebot:group | onebot:chat_type | 来自OneBot的私聊消息 | | 仅当消息来自群聊时存在 | +| group | chat_type | 私聊消息 | | 仅当消息来自私聊时存在 | | | | +| \ | platform | 来自\的用户 | qq | | +| onebot | onebot | 来自OneBot的用户 | | | +| all | all | 所有用户 | | | ## 主体定义(两级群组) 从上往下优先级从高到低 -| 主体 | 含义 | 示例 | 存在条件 | -|-------------------------------------------------|----------------|----------------------------------------|---------------| -| \:g:c: | 服务器频道用户 | telegram:g87654321:c123454321:12345678 | 仅当消息来自频道时存在 | -| onebot:g:c: | 服务器频道用户 | onebot:g87654321:c123454321:12345678 | 仅当消息来自频道时存在 | -| \:c: | 频道用户 | telegram:c123454321:12345678 | 仅当消息来自频道时存在 | -| onebot:c: | 频道用户 | onebot:c123454321:12345678 | 仅当消息来自频道时存在 | -| \:g: | 服务器用户 | telegram:g87654321:12345678 | 仅当消息来自服务器时存在 | -| onebot:g: | 服务器用户 | onebot:g87654321:12345678 | 仅当消息来自服务器时存在 | -| \: | 用户 | telegram:12345678 | | -| onebot: | 用户 | onebot:12345678 | | -| superuser | 超级用户 | | 仅当该用户为超级用户时存在 | -| \:g:c | 服务器频道 | telegram:g87654321:c123454321 | 仅当消息来自频道时存在 | -| onebot:g:c | 服务器频道 | onebot:g87654321:c123454321 | 仅当消息来自频道时存在 | -| \:c | 频道 | telegram:c123454321 | 仅当消息来自频道时存在 | -| onebot:c | 频道 | onebot:c123454321 | 仅当消息来自频道时存在 | -| \:g | 服务器 | telegram:g87654321 | 仅当消息来自频道时存在 | -| onebot:g | 服务器 | onebot:g87654321 | 仅当消息来自频道时存在 | -| \:private | 私聊消息 | qq:private | 仅当消息来自私聊时存在 | -| onebot:private | 私聊消息(与上一条含义相同) | | 仅当消息来自私聊时存在 | -| \:channel | 频道消息 | telegram:channel | 仅当消息来自频道时存在 | -| onebot:channel | 频道消息(与上一条含义相同) | | 仅当消息来自频道时存在 | -| \ | 某个平台用户 | qq | | -| onebot | OneBot用户 | | | -| all | 所有用户 | | | +| 主体 | TAG | 含义 | 示例 | 存在条件 | +|-------------------------------------------------|-----------------------------|-----------------------|----------------------------------------|---------------| +| \:g:c: | platform:guild:channel:user | 来自\的服务器频道用户 | telegram:g87654321:c123454321:12345678 | 仅当消息来自频道时存在 | +| onebot:g:c: | onebot:guild:channel:user | 来自OneBot的服务器频道用户 | onebot:g87654321:c123454321:12345678 | 仅当消息来自频道时存在 | +| \:c: | platform:channel:user | 来自\的频道用户 | telegram:c123454321:12345678 | 仅当消息来自频道时存在 | +| onebot:c: | onebot:channel:user | 来自OneBot的频道用户 | onebot:c123454321:12345678 | 仅当消息来自频道时存在 | +| \:g: | platform:guild:user | 来自\的服务器用户 | telegram:g87654321:12345678 | 仅当消息来自服务器时存在 | +| onebot:g: | onebot:guild:user | 来自OneBot的服务器用户 | onebot:g87654321:12345678 | 仅当消息来自服务器时存在 | +| \: | platform:user | 来自\的用户 | telegram:12345678 | | +| onebot: | onebot:user | 来自OneBot的用户 | onebot:12345678 | | +| superuser | superuser | 超级用户 | | 仅当该用户为超级用户时存在 | +| \:g:c | platform:guild:channel | 来自\的服务器频道 | telegram:g87654321:c123454321 | 仅当消息来自频道时存在 | +| onebot:g:c | onebot:guild:channel | 来自OneBot的服务器频道 | onebot:g87654321:c123454321 | 仅当消息来自频道时存在 | +| \:c | platform:channel | 来自\的频道 | telegram:c123454321 | 仅当消息来自频道时存在 | +| onebot:c | onebot:channel | 来自OneBot的频道 | onebot:c123454321 | 仅当消息来自频道时存在 | +| \:g | platform:guild | 来自\的服务器 | telegram:g87654321 | 仅当消息来自频道时存在 | +| onebot:g | onebot:guild | 来自OneBot的服务器 | onebot:g87654321 | 仅当消息来自频道时存在 | +| \:private | platform:private | 来自\的私聊消息 | qq:private | 仅当消息来自私聊时存在 | +| onebot:private | onebot:private | 来自OneBot的私聊消息 | | 仅当消息来自私聊时存在 | +| private | private | 私聊消息 | | 仅当消息来自私聊时存在 | +| \:channel | platform:channel | 来自\的频道消息 | telegram:channel | 仅当消息来自频道时存在 | +| onebot:channel | onebot:channel | 来自OneBot的频道消息 | | 仅当消息来自频道时存在 | +| channel | channel | 频道消息 | +| \ | platform | 来自\的用户 | qq | | +| onebot | onebot | 来自OneBot的用户 | | | +| all | all | 所有用户 | | | diff --git a/docs/qqguild.md b/docs/qqguild.md index 439c9a9..0529521 100644 --- a/docs/qqguild.md +++ b/docs/qqguild.md @@ -5,26 +5,27 @@ nonebot-plugin-access-control for QQ Guild 从上往下优先级从高到低 -| 主体 | 含义 | 示例 | 存在条件 | -|-------------------------------------------------|---------|--------------------------------------------|-----------------------| -| qqguild:g:c: | 服务器频道用户 | qqguild:g87654321:c123454321:12345678 | 仅当消息来自频道时存在 | -| qqguild:c: | 频道用户 | qqguild:c123454321:12345678 | 仅当消息来自频道时存在 | -| qqguild:g: | 服务器用户 | qqguild:g87654321:12345678 | 仅当消息来自频道时存在 | -| qqguild: | 用户 | qqguild:12345678 | | -| superuser | 超级用户 | | 仅当该用户为超级用户时存在 | -| qqguild:g.guild_owner | 服务器主 | qqguild:g87654321.guild_owner | 仅当消息来自频道、该用户为服务器主时存在 | -| qqguild:guild_owner | 服务器主 | | 仅当消息来自频道、该用户为服务器主时存在 | -| qqguild:g.guild_admin | 服务器管理 | qqguild:g87654321.guild_admin | 仅当消息来自频道、该用户为服务器管理时存在 | -| qqguild:guild_admin | 服务器管理 | | 仅当消息来自频道、该用户为服务器管理时存在 | -| qqguild:g:c.channel_admin | 频道管理 | qqguild:g87654321:c123454321.channel_admin | 仅当消息来自频道、该用户为频道管理时存在 | -| qqguild:c.channel_admin | 频道管理 | qqguild:c123454321.channel_admin | 仅当消息来自频道、该用户为频道管理时存在 | -| qqguild:g.channel_admin | 频道管理 | qqguild:g87654321.channel_admin | 仅当消息来自频道、该用户为频道管理时存在 | -| qqguild:channel_admin | 频道管理 | | 仅当消息来自频道、该用户为频道管理时存在 | -| qqguild:g.role_\ | 服务器身份组 | qqguild:g87654321.role_233 | 仅当消息来自频道、该用户在该身份组时存在 | -| qqguild:g:c | 服务器频道 | qqguild:g87654321:c123454321 | 仅当消息来自频道时存在 | -| qqguild:c | 频道 | qqguild:c123454321 | 仅当消息来自频道时存在 | -| qqguild:g | 服务器 | qqguild:g87654321 | 仅当消息来自频道时存在 | -| qqguild:private | 私聊消息 | | 仅当消息来自私聊时存在 | -| qqguild:channel | 频道消息 | | 仅当消息来自频道时存在 | -| qqguild | 某个平台用户 | | | -| all | 所有用户 | | | +| 主体 | TAG | 含义 | 示例 | 存在条件 | +|-------------------------------------------------|-------------------------------------|-------------|--------------------------------------------|-----------------------| +| qqguild:g:c: | platform:guild:channel:user | 服务器频道用户 | qqguild:g87654321:c123454321:12345678 | 仅当消息来自频道时存在 | +| qqguild:c: | platform:channel:user | 频道用户 | qqguild:c123454321:12345678 | 仅当消息来自频道时存在 | +| qqguild:g: | platform:guild:user | 服务器用户 | qqguild:g87654321:12345678 | 仅当消息来自频道时存在 | +| qqguild: | platform:user | 用户 | qqguild:12345678 | | +| superuser | superuser | 超级用户 | | 仅当该用户为超级用户时存在 | +| qqguild:g.guild_owner | qqguild:guild.guild_owner | 服务器主 | qqguild:g87654321.guild_owner | 仅当消息来自频道、该用户为服务器主时存在 | +| qqguild:guild_owner | qqguild:guild_owner | 服务器主 | | 仅当消息来自频道、该用户为服务器主时存在 | +| qqguild:g.guild_admin | qqguild:guild.guild_admin | 服务器管理 | qqguild:g87654321.guild_admin | 仅当消息来自频道、该用户为服务器管理时存在 | +| qqguild:guild_admin | qqguild:guild_admin | 服务器管理 | | 仅当消息来自频道、该用户为服务器管理时存在 | +| qqguild:g:c.channel_admin | qqguild:guild:channel.channel_admin | 频道管理 | qqguild:g87654321:c123454321.channel_admin | 仅当消息来自频道、该用户为频道管理时存在 | +| qqguild:c.channel_admin | qqguild:channel.channel_admin | 频道管理 | qqguild:c123454321.channel_admin | 仅当消息来自频道、该用户为频道管理时存在 | +| qqguild:channel_admin | qqguild:channel_admin | 频道管理 | | 仅当消息来自频道、该用户为频道管理时存在 | +| qqguild:g.role_\ | qqguild:guild.role | 服务器身份组 | qqguild:g87654321.role_233 | 仅当消息来自频道、该用户在该身份组时存在 | +| qqguild:g:c | platform:guild:channel | 服务器频道 | qqguild:g87654321:c123454321 | 仅当消息来自频道时存在 | +| qqguild:c | platform:channel | 频道 | qqguild:c123454321 | 仅当消息来自频道时存在 | +| qqguild:g | platform:guild | 服务器 | qqguild:g87654321 | 仅当消息来自频道时存在 | +| qqguild:private | platform:private | 来自QQ频道的私聊消息 | | 仅当消息来自私聊时存在 | +| private | private | 私聊消息 | | 仅当消息来自私聊时存在 | | | +| qqguild:channel | platform:channel | 来自QQ频道的频道消息 | | 仅当消息来自频道时存在 | +| channel | channel | 频道消息 | | 仅当消息来自频道是存在 | +| qqguild | platform | 来自QQ频道的用户 | | | +| all | all | 所有用户 | | | diff --git a/poetry.lock b/poetry.lock index 357f185..d8a3842 100644 --- a/poetry.lock +++ b/poetry.lock @@ -91,19 +91,19 @@ zookeeper = ["kazoo"] [[package]] name = "arclet-alconna" -version = "1.7.22" +version = "1.7.24" description = "A High-performance, Generality, Humane Command Line Arguments Parser Library." category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "arclet_alconna-1.7.22-py3-none-any.whl", hash = "sha256:7591d8a191bab7b8e59dfe933c3be4a937e13044500ea25618281f9e17d34f18"}, - {file = "arclet_alconna-1.7.22.tar.gz", hash = "sha256:68c408b249f8c2cd15675e315aa6beb4050bcd40bcb275ce126a98886c465275"}, + {file = "arclet_alconna-1.7.24-py3-none-any.whl", hash = "sha256:fe2fcfd170da7985810f1bd68051288b56f586f08b154d744c7db4fba890d94e"}, + {file = "arclet_alconna-1.7.24.tar.gz", hash = "sha256:e10fce577be3de3f326890a0a80410a83fad41adff71db241007bb43b09ba846"}, ] [package.dependencies] nepattern = ">=0.5.14,<0.6.0" -tarina = ">=0.3.3" +tarina = ">=0.4.1" typing-extensions = ">=4.5.0" [package.extras] diff --git a/pyproject.toml b/pyproject.toml index b13db7e..b60d00a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "nonebot-plugin-access-control" -version = "0.7.0" +version = "0.8.0" description = "" authors = ["ssttkkl "] license = "MIT" diff --git a/src/nonebot_plugin_access_control/subject/extractor/__init__.py b/src/nonebot_plugin_access_control/subject/extractor/__init__.py index 9953472..13761eb 100644 --- a/src/nonebot_plugin_access_control/subject/extractor/__init__.py +++ b/src/nonebot_plugin_access_control/subject/extractor/__init__.py @@ -28,13 +28,21 @@ def add_subject_extractor(extractor: T_SubjectExtractor) -> T_SubjectExtractor: def extract_subjects(bot: Bot, event: Event) -> Sequence[str]: - sbj = extractor_chain(bot, event, []) + sbj = [ + x.content + for x in + extractor_chain(bot, event, []) + ] logger.debug("subjects: " + ', '.join(sbj)) return sbj def extract_subjects_from_session(session: Session) -> Sequence[str]: - sbj = extract_from_session(session) + sbj = [ + x.content + for x in + extract_from_session(session) + ] logger.debug("subjects: " + ', '.join(sbj)) return sbj diff --git a/src/nonebot_plugin_access_control/subject/extractor/base.py b/src/nonebot_plugin_access_control/subject/extractor/base.py index 031a374..e632961 100644 --- a/src/nonebot_plugin_access_control/subject/extractor/base.py +++ b/src/nonebot_plugin_access_control/subject/extractor/base.py @@ -3,17 +3,19 @@ from nonebot import Bot, logger from nonebot.internal.adapter import Event -T_SubjectExtractor = Callable[[Bot, Event, Sequence[str]], Sequence[str]] +from ..model import SubjectModel + +T_SubjectExtractor = Callable[[Bot, Event, Sequence[SubjectModel]], Sequence[SubjectModel]] class SubjectExtractorChain: def __init__(self, *extractors: T_SubjectExtractor): self.extractors = list(extractors) - def __call__(self, bot: Bot, event: Event, current: Sequence[str]) -> Sequence[str]: + def __call__(self, bot: Bot, event: Event, current: Sequence[SubjectModel]) -> Sequence[SubjectModel]: for ext in self.extractors: current = ext(bot, event, current) - logger.trace("current subjects: " + ', '.join(current)) + logger.trace("current subjects: " + ', '.join(map(str, current))) return current def add(self, extractor: T_SubjectExtractor): diff --git a/src/nonebot_plugin_access_control/subject/extractor/builtin/kaiheila.py b/src/nonebot_plugin_access_control/subject/extractor/builtin/kaiheila.py index 9be492e..cbb6c07 100644 --- a/src/nonebot_plugin_access_control/subject/extractor/builtin/kaiheila.py +++ b/src/nonebot_plugin_access_control/subject/extractor/builtin/kaiheila.py @@ -1,18 +1,20 @@ -from typing import TYPE_CHECKING, Optional, Sequence +from typing import TYPE_CHECKING, Optional, Sequence, List from nonebot import Bot from nonebot.internal.adapter import Event +from ...model import SubjectModel + if TYPE_CHECKING: from nonebot.adapters.kaiheila.event import User, Event as KaiheilaEvent +OFFER_BY = "nonebot_plugin_access_control" + -def extract_kaiheila_role(bot: Bot, event: Event, current: Sequence[str]) -> Sequence[str]: +def extract_kaiheila_role(bot: Bot, event: Event, current: Sequence[SubjectModel]) -> Sequence[SubjectModel]: if bot.type != "Kaiheila": return current - li = [*current] - event: KaiheilaEvent guild_id: Optional[str] = event.extra.guild_id @@ -20,9 +22,19 @@ def extract_kaiheila_role(bot: Bot, event: Event, current: Sequence[str]) -> Seq author: Optional['User'] = event.extra.author if author is not None: - # 添加qqguild:role_xxx的subject(在"kaiheila:g{guild_id}:c{channel_id}"之前) - idx = li.index(f"kaiheila:g{guild_id}:c{channel_id}") - for role in reversed(sorted(author.roles)): - li.insert(idx, f"kaiheila:g{guild_id}.role_{role}") + li = [] + + for role in sorted(author.roles): + li.append(SubjectModel(f"kaiheila:g{guild_id}.role_{role}", OFFER_BY, + f"kaiheila:guild.role")) + + # 添加在platform_guild_channel之前 + idx = 0 + for i in range(len(current)): + if current[i].tag == "platform:guild:channel": + idx = i + break + + current = [*current[:idx], *li, *current[idx:]] - return li + return current diff --git a/src/nonebot_plugin_access_control/subject/extractor/builtin/onebot_v11.py b/src/nonebot_plugin_access_control/subject/extractor/builtin/onebot_v11.py index af9bb1d..944c360 100644 --- a/src/nonebot_plugin_access_control/subject/extractor/builtin/onebot_v11.py +++ b/src/nonebot_plugin_access_control/subject/extractor/builtin/onebot_v11.py @@ -3,28 +3,43 @@ from nonebot import Bot from nonebot.internal.adapter import Event +from ...model import SubjectModel + if TYPE_CHECKING: from nonebot.adapters.onebot.v11.event import Sender +OFFER_BY = "nonebot_plugin_access_control" + -def extract_onebot_v11_group_role(bot: Bot, event: Event, current: Sequence[str]) -> Sequence[str]: +def extract_onebot_v11_group_role(bot: Bot, event: Event, current: Sequence[SubjectModel]) -> Sequence[SubjectModel]: if bot.type != "OneBot V11": return current - li = [*current] - group_id = getattr(event, "group_id", None) sender: Optional['Sender'] = getattr(event, "sender", None) if group_id is not None and sender is not None: - # 添加群管理/群主的subject(在"qq:g{group_id}"之前) - idx = li.index(f"qq:g{group_id}") + li = [] + if sender.role == 'owner': - li.insert(idx, f"qq:group_owner") - li.insert(idx, f"qq:g{group_id}.group_owner") + li.append(SubjectModel(f"qq:g{group_id}.group_owner", OFFER_BY, + f"qq:group.group_owner")) + li.append(SubjectModel(f"qq:group_owner", OFFER_BY, + f"qq:group_owner")) if sender.role == 'owner' or sender.role == 'admin': - li.insert(idx, f"qq:group_admin") - li.insert(idx, f"qq:g{group_id}.group_admin") + li.append(SubjectModel(f"qq:g{group_id}.group_admin", OFFER_BY, + f"qq:group.group_admin")) + li.append(SubjectModel(f"qq:group_admin", OFFER_BY, + f"qq:group_admin")) + + # 添加在platform_group之前 + idx = 0 + for i in range(len(current)): + if current[i].tag == "platform:group": + idx = i + break + + current = [*current[:idx], *li, *current[idx:]] - return li + return current diff --git a/src/nonebot_plugin_access_control/subject/extractor/builtin/qqguild.py b/src/nonebot_plugin_access_control/subject/extractor/builtin/qqguild.py index b9b80e0..bf8a482 100644 --- a/src/nonebot_plugin_access_control/subject/extractor/builtin/qqguild.py +++ b/src/nonebot_plugin_access_control/subject/extractor/builtin/qqguild.py @@ -1,19 +1,25 @@ -from typing import TYPE_CHECKING, Optional, Sequence +from typing import TYPE_CHECKING, Optional, Sequence, List from nonebot import Bot from nonebot.internal.adapter import Event +from ...model import SubjectModel + if TYPE_CHECKING: from nonebot.adapters.qqguild.event import Member +OFFER_BY = "nonebot_plugin_access_control" + PRESET_ROLES = { 2: "guild_admin", 4: "guild_owner", 5: "channel_admin" } +PRESET_ROLE_PRIORITY = (4, 2, 5) -def extract_qqguild_role(bot: Bot, event: Event, current: Sequence[str]) -> Sequence[str]: + +def extract_qqguild_role(bot: Bot, event: Event, current: Sequence[SubjectModel]) -> Sequence[SubjectModel]: if bot.type != "QQ Guild": return current @@ -21,23 +27,41 @@ def extract_qqguild_role(bot: Bot, event: Event, current: Sequence[str]) -> Sequ if is_direct_msg: return current - li = [*current] - guild_id: Optional[str] = getattr(event, "guild_id", None) channel_id: Optional[str] = getattr(event, "channel_id", None) member: Optional['Member'] = getattr(event, "member", None) if member is not None: - # 添加qqguild:role_xxx的subject(在"qqguild:g{guild_id}:c{channel_id}"之前) - idx = li.index(f"qqguild:g{guild_id}:c{channel_id}") - for role in reversed(sorted(member.roles)): - if role in PRESET_ROLES: - li.insert(idx, f"qqguild:{PRESET_ROLES[role]}") - li.insert(idx, f"qqguild:g{guild_id}.{PRESET_ROLES[role]}") - if role == 5: # 频道管理员 - li.insert(idx, f"qqguild:c{channel_id}.{PRESET_ROLES[role]}") - li.insert(idx, f"qqguild:g{guild_id}:c{channel_id}.{PRESET_ROLES[role]}") + li = [] + + for actual_role in sorted(member.roles): + if actual_role in PRESET_ROLES: + # 我们默认优先级高的预置角色(例如服务器主)继承优先级低的(例如频道管理员) + priority = PRESET_ROLE_PRIORITY.index(actual_role) + for i in range(priority, len(PRESET_ROLE_PRIORITY)): + role = PRESET_ROLE_PRIORITY[i] + + if role == 5: # 频道管理员 + li.append(SubjectModel(f"qqguild:g{guild_id}:c{channel_id}.{PRESET_ROLES[role]}", OFFER_BY, + f"qqguild:guild:channel.{PRESET_ROLES[role]}")) + li.append(SubjectModel(f"qqguild:c{channel_id}.{PRESET_ROLES[role]}", OFFER_BY, + f"qqguild:channel:{PRESET_ROLES[role]}")) + else: + li.append(SubjectModel(f"qqguild:g{guild_id}.{PRESET_ROLES[role]}", OFFER_BY, + f"qqguild:guild.{PRESET_ROLES[role]}")) + li.append(SubjectModel(f"qqguild:{PRESET_ROLES[role]}", OFFER_BY, + f"qqguild:{PRESET_ROLES[role]}")) else: - li.insert(idx, f"qqguild:g{guild_id}.role_{role}") + li.append(SubjectModel(f"qqguild:g{guild_id}.role_{actual_role}", OFFER_BY, + f"qqguild:guild.role")) + + # 添加在platform_guild_channel之前 + idx = 0 + for i in range(len(current)): + if current[i].tag == "platform:guild:channel": + idx = i + break + + current = [*current[:idx], *li, *current[idx:]] - return li + return current diff --git a/src/nonebot_plugin_access_control/subject/extractor/builtin/session.py b/src/nonebot_plugin_access_control/subject/extractor/builtin/session.py index ceada1b..6d790bb 100644 --- a/src/nonebot_plugin_access_control/subject/extractor/builtin/session.py +++ b/src/nonebot_plugin_access_control/subject/extractor/builtin/session.py @@ -4,70 +4,92 @@ from nonebot.internal.adapter import Event from nonebot_plugin_session import extract_session, SessionLevel, Session +from ...model import SubjectModel from ....utils.superuser import is_superuser +OFFER_BY = "nonebot_plugin_access_control" -def _append_with_tags(li: List[str], body: str, tags: Sequence[str]): - for t in tags: - li.append(f"{t}:{body}") +def _append_subject(li: List[SubjectModel], + content_body: str, content_prefix: Sequence[str], + tag: Sequence[str]): + for i in range(min(len(content_prefix), len(tag))): + li.append(SubjectModel(f"{content_prefix[i]}{content_body}", OFFER_BY, tag[i])) -def extract_from_session(session: Session) -> Sequence[str]: + +def extract_from_session(session: Session) -> Sequence[SubjectModel]: if session.bot_type == "OneBot V11" or session.bot_type == "OneBot V12": - tags = [session.platform, "onebot"] + prefix = [session.platform, "onebot"] else: - tags = [session.platform] + prefix = [session.platform] - li = [] + li: List[SubjectModel] = [] if session.level == SessionLevel.LEVEL3: user_id = session.id1 channel_id = session.id2 guild_id = session.id3 - _append_with_tags(li, f"g{guild_id}:c{channel_id}:{user_id}", tags) - _append_with_tags(li, f"c{channel_id}:{user_id}", tags) - _append_with_tags(li, f"g{guild_id}:{user_id}", tags) - _append_with_tags(li, f"{user_id}", tags) + _append_subject(li, f":g{guild_id}:c{channel_id}:{user_id}", prefix, + ["platform:guild:channel:user", "onebot:guild:channel:user"]) + _append_subject(li, f":c{channel_id}:{user_id}", prefix, + ["platform:channel:user", "onebot:channel:user"]) + _append_subject(li, f":g{guild_id}:{user_id}", prefix, + ["platform:guild:user", "onebot:guild:user"]) + _append_subject(li, f":{user_id}", prefix, + ["platform:user", "onebot:user"]) if is_superuser(user_id, session.bot_type): - li.append("superuser") - - _append_with_tags(li, f"g{guild_id}:c{channel_id}", tags) - _append_with_tags(li, f"c{channel_id}", tags) - _append_with_tags(li, f"g{guild_id}", tags) - - _append_with_tags(li, f"channel", tags) + li.append(SubjectModel("superuser", OFFER_BY, "superuser")) + + _append_subject(li, f":g{guild_id}:c{channel_id}", prefix, + ["platform:guild:channel", "onebot:guild:channel"]) + _append_subject(li, f":c{channel_id}", prefix, + ["platform:channel", "onebot:channel"]) + _append_subject(li, f":g{guild_id}", prefix, + ["platform:guild", "onebot:guild"]) + + _append_subject(li, ":channel", prefix, + ["platform:chat_type", "onebot:chat_type"]) + li.append(SubjectModel("channel", OFFER_BY, "chat_type")) elif session.level == SessionLevel.LEVEL2: user_id = session.id1 group_id = session.id2 - _append_with_tags(li, f"g{group_id}:{user_id}", tags) - _append_with_tags(li, f"{user_id}", tags) + _append_subject(li, f":g{group_id}:{user_id}", prefix, + ["platform:group:user", "onebot:group:user"]) + _append_subject(li, f":{user_id}", prefix, + ["platform:user", "onebot:user"]) if is_superuser(user_id, session.bot_type): - li.append("superuser") + li.append(SubjectModel("superuser", OFFER_BY, "superuser")) - _append_with_tags(li, f"g{group_id}", tags) - _append_with_tags(li, f"group", tags) + _append_subject(li, f":g{group_id}", prefix, + ["platform:group", "onebot:group"]) + _append_subject(li, ":group", prefix, + ["platform:chat_type", "onebot:chat_type"]) + li.append(SubjectModel("group", OFFER_BY, "chat_type")) elif session.level == SessionLevel.LEVEL1: user_id = session.id1 - _append_with_tags(li, f"{user_id}", tags) + _append_subject(li, f":{user_id}", prefix, + ["platform:user", "onebot:user"]) if is_superuser(user_id, session.bot_type): - li.append("superuser") + li.append(SubjectModel("superuser", OFFER_BY, "superuser")) - _append_with_tags(li, f"private", tags) + _append_subject(li, ":private", prefix, + ["platform:chat_type", "onebot:chat_type"]) + li.append(SubjectModel("private", OFFER_BY, "chat_type")) - for t in tags: - li.append(t) + _append_subject(li, "", prefix, + ["platform", "onebot"]) - li.append("all") + li.append(SubjectModel("all", OFFER_BY, "all")) return li -def extract_by_session(bot: Bot, event: Event, current: Sequence[str]) -> Sequence[str]: +def extract_by_session(bot: Bot, event: Event, current: Sequence[SubjectModel]) -> Sequence[SubjectModel]: session = extract_session(bot, event) return [*current, *extract_from_session(session)] diff --git a/src/nonebot_plugin_access_control/subject/model.py b/src/nonebot_plugin_access_control/subject/model.py new file mode 100644 index 0000000..298dd81 --- /dev/null +++ b/src/nonebot_plugin_access_control/subject/model.py @@ -0,0 +1,13 @@ +from typing import Optional, NamedTuple + + +class SubjectModel(NamedTuple): + content: str + offer_by: str + tag: Optional[str] + + def __str__(self): + return self.content + + def __repr__(self): + return f"{self.content} (tag: {self.tag}, offer by: {self.offer_by})"