-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
提供统一的用户,支持绑定各平台用户。
- Loading branch information
Showing
17 changed files
with
1,372 additions
and
169 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import random | ||
from typing import cast | ||
|
||
from expiringdict import ExpiringDict | ||
from nonebot_plugin_alconna import ( | ||
Alconna, | ||
AlconnaQuery, | ||
Args, | ||
Option, | ||
Query, | ||
on_alconna, | ||
) | ||
from nonebot_plugin_session import SessionLevel | ||
|
||
from .annotated import UserSession | ||
from .utils import get_user, remove_bind, set_bind | ||
|
||
user_cmd = on_alconna(Alconna("user"), use_cmd_start=True) | ||
|
||
|
||
@user_cmd.handle() | ||
async def _(session: UserSession): | ||
await user_cmd.finish( | ||
"\n".join( | ||
[ | ||
f"用户 ID:{session.uid}", | ||
f"用户名:{session.name}", | ||
f"用户创建日期:{session.created_at}", | ||
f"用户所在平台 ID:{session.pid}", | ||
f"用户所在平台:{session.platform}", | ||
] | ||
) | ||
) | ||
|
||
|
||
tokens = cast( | ||
dict[str, tuple[str, str, int, SessionLevel | None]], | ||
ExpiringDict(max_len=100, max_age_seconds=300), | ||
) | ||
|
||
|
||
bind_cmd = on_alconna( | ||
Alconna("bind", Option("-r"), Args["token?", str]), use_cmd_start=True | ||
) | ||
|
||
|
||
@bind_cmd.handle() | ||
async def _( | ||
session: UserSession, | ||
token: str | None = None, | ||
remove: Query[bool] = AlconnaQuery("r.value", default=False), | ||
): | ||
if remove.result: | ||
result = await remove_bind(session.pid, session.platform) | ||
if result: | ||
await bind_cmd.finish("解绑成功") | ||
else: | ||
await bind_cmd.finish("不能解绑最初绑定的账号") | ||
|
||
# 生成令牌 | ||
if not token: | ||
token = f"nonebot/{random.randint(100000, 999999)}" | ||
tokens[token] = (session.pid, session.platform, session.uid, session.level) | ||
await bind_cmd.finish( | ||
f"命令 bind 可用于在多个平台间绑定用户数据。绑定过程中,原始平台的用户数据将完全保留,而目标平台的用户数据将被原始平台的数据所覆盖。\n请确认当前平台是你的目标平台,并在 5 分钟内使用你的账号在原始平台内向机器人发送以下文本:\n/bind {token}\n绑定完成后,你可以随时使用「bind -r」来解除绑定状态。" | ||
) | ||
|
||
# 绑定流程 | ||
if token in tokens: | ||
# 平台的相关信息 | ||
pid, platform, user_id, level = tokens.pop(token) | ||
# 群内绑定的第一步,会在原始平台发送令牌 | ||
# 此时 pid 和 platform 为目标平台的信息 | ||
if level == SessionLevel.LEVEL2 or level == SessionLevel.LEVEL3: | ||
token = f"nonebot/{random.randint(100000, 999999)}" | ||
tokens[token] = (session.pid, session.platform, user_id, None) | ||
await bind_cmd.finish( | ||
f"令牌核验成功!下面将进行第二步操作。\n请在 5 分钟内使用你的账号在目标平台内向机器人发送以下文本:\n/bind {token}\n注意:当前平台是你的原始平台,这里的用户数据将覆盖目标平台的数据。" | ||
) | ||
# 群内绑定的第二步,会在目标平台发送令牌 | ||
# 此时 pid 和 platform 为原始平台的信息 | ||
# 需要重新获取其用户信息,然后将目标平台绑定至原始平台 | ||
elif level is None: | ||
if session.uid != user_id: | ||
await bind_cmd.finish("请使用最开始要绑定账号进行操作") | ||
|
||
user = await get_user(pid, platform) | ||
await set_bind(session.pid, session.platform, user.id) | ||
await bind_cmd.finish("绑定成功") | ||
# 私聊绑定时,会在原始平台发送令牌 | ||
# 此时 pid 和 platform 为目标平台的信息 | ||
# 直接将目标平台绑定至原始平台 | ||
elif level == SessionLevel.LEVEL1: | ||
await set_bind(pid, platform, session.uid) | ||
await bind_cmd.finish("绑定成功") | ||
else: | ||
await bind_cmd.finish("令牌不存在或已过期") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from typing import Annotated | ||
|
||
from nonebot.params import Depends | ||
|
||
from .depends import UserSession as _UserSession | ||
from .depends import get_or_create_user, get_user_session | ||
from .models import User as _User | ||
|
||
User = Annotated[_User, Depends(get_or_create_user)] | ||
UserSession = Annotated[_UserSession, Depends(get_user_session)] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
from nonebot.matcher import Matcher | ||
from nonebot.params import Depends | ||
from nonebot_plugin_session import Session, SessionLevel, extract_session | ||
from nonebot_plugin_userinfo import EventUserInfo, UserInfo | ||
|
||
from . import utils | ||
from .models import UserSession | ||
|
||
|
||
async def get_or_create_user( | ||
matcher: Matcher, | ||
session: Session = Depends(extract_session), | ||
user_info: UserInfo | None = EventUserInfo(), | ||
): | ||
"""获取一个用户,如果不存在则创建""" | ||
if ( | ||
session.platform == "unknown" | ||
or session.level == SessionLevel.LEVEL0 | ||
or not session.id1 | ||
): | ||
await matcher.finish("用户相关功能暂不支持当前平台") | ||
raise ValueError("用户相关功能暂不支持当前平台") | ||
|
||
try: | ||
user = await utils.get_user(session.id1, session.platform) | ||
except ValueError: | ||
user = await utils.create_user( | ||
session.id1, | ||
session.platform, | ||
user_info and user_info.user_name or session.id1, | ||
) | ||
|
||
return user | ||
|
||
|
||
async def get_user_session( | ||
matcher: Matcher, | ||
session: Session = Depends(extract_session), | ||
user_info: UserInfo | None = EventUserInfo(), | ||
): | ||
"""获取用户会话""" | ||
user = await get_or_create_user(matcher, session, user_info) | ||
return UserSession(session, user_info, user) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
"""init db | ||
Revision ID: 5cb13347bece | ||
Revises: | ||
Create Date: 2023-09-12 17:07:22.228191 | ||
""" | ||
import sqlalchemy as sa | ||
from alembic import op | ||
|
||
# revision identifiers, used by Alembic. | ||
revision = "5cb13347bece" | ||
down_revision = None | ||
branch_labels = None | ||
depends_on = None | ||
|
||
|
||
def upgrade() -> None: | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.create_table( | ||
"user_user", | ||
sa.Column("id", sa.Integer(), nullable=False), | ||
sa.Column("name", sa.String(length=255), nullable=False), | ||
sa.Column("created_at", sa.DateTime(), nullable=False), | ||
sa.PrimaryKeyConstraint("id"), | ||
) | ||
op.create_table( | ||
"user_bind", | ||
sa.Column("pid", sa.String(length=64), nullable=False), | ||
sa.Column("platform", sa.String(length=32), nullable=False), | ||
sa.Column("aid", sa.Integer(), nullable=False), | ||
sa.Column("bid", sa.Integer(), nullable=False), | ||
sa.ForeignKeyConstraint( | ||
["aid"], | ||
["user_user.id"], | ||
), | ||
sa.ForeignKeyConstraint( | ||
["bid"], | ||
["user_user.id"], | ||
), | ||
sa.PrimaryKeyConstraint("pid", "platform"), | ||
) | ||
# ### end Alembic commands ### | ||
|
||
|
||
def downgrade() -> None: | ||
# ### commands auto generated by Alembic - please adjust! ### | ||
op.drop_table("user_bind") | ||
op.drop_table("user_user") | ||
# ### end Alembic commands ### |
Oops, something went wrong.