diff --git a/core/services/players/models.py b/core/services/players/models.py index 8962235e..32aedd2f 100644 --- a/core/services/players/models.py +++ b/core/services/players/models.py @@ -24,7 +24,7 @@ class Player(SQLModel): default=None, primary_key=True, sa_column=Column(Integer(), primary_key=True, autoincrement=True) ) user_id: int = Field(primary_key=True, sa_column=Column(BigInteger())) - account_id: int = Field(primary_key=True, sa_column=Column(BigInteger())) + account_id: int = Field(default=None, primary_key=True, sa_column=Column(BigInteger())) player_id: int = Field(primary_key=True, sa_column=Column(BigInteger())) region: RegionEnum = Field(sa_column=Column(Enum(RegionEnum))) is_chosen: Optional[bool] = Field(sa_column=Column(Boolean)) diff --git a/plugins/account/account.py b/plugins/account/account.py index 7fd2a4fc..e153d33c 100644 --- a/plugins/account/account.py +++ b/plugins/account/account.py @@ -3,7 +3,6 @@ from typing import Optional import genshin from genshin import DataNotPublic, GenshinException, types -from genshin.models import RecordCard from telegram import ReplyKeyboardMarkup, ReplyKeyboardRemove, TelegramObject, Update from telegram.ext import CallbackContext, ConversationHandler, filters from telegram.helpers import escape_markdown @@ -21,19 +20,18 @@ __all__ = ("BindAccountPlugin",) class BindAccountPluginData(TelegramObject): player: Optional[Player] = None - record_card: Optional[RecordCard] = None region: RegionEnum = RegionEnum.HYPERION - account_id: int = 0 - # player_id: int = 0 + player_id: Optional[int] = None + nickname: Optional[str] = None def reset(self): self.player = None self.region = RegionEnum.NULL - self.account_id = 0 - self.record_card = None + self.player_id = None + self.nickname = None -CHECK_SERVER, CHECK_UID, COMMAND_RESULT = range(10100, 10103) +CHECK_SERVER, CHECK_METHOD, CHECK_ACCOUNT_ID, CHECK_PLAYER_ID, COMMAND_RESULT = range(10100, 10105) class BindAccountPlugin(Plugin.Conversation): @@ -52,7 +50,7 @@ class BindAccountPlugin(Plugin.Conversation): self.player_info_service = player_info_service @conversation.entry_point - @handler.command(command="setuid", filters=filters.ChatType.PRIVATE, block=True) + @handler.command(command="setuid", filters=filters.ChatType.PRIVATE, block=False) async def command_start(self, update: Update, context: CallbackContext) -> int: user = update.effective_user message = update.effective_message @@ -72,7 +70,7 @@ class BindAccountPlugin(Plugin.Conversation): return CHECK_SERVER @conversation.state(state=CHECK_SERVER) - @handler.message(filters=filters.TEXT & ~filters.COMMAND, block=True) + @handler.message(filters=filters.TEXT & ~filters.COMMAND, block=False) async def check_server(self, update: Update, context: CallbackContext) -> int: message = update.effective_message bind_account_plugin_data: BindAccountPluginData = context.chat_data.get("bind_account_plugin_data") @@ -86,12 +84,31 @@ class BindAccountPlugin(Plugin.Conversation): else: await message.reply_text("选择错误,请重新选择") return CHECK_SERVER - await message.reply_text("请输入你的通行证ID(非玩家ID)", reply_markup=ReplyKeyboardRemove()) - return CHECK_UID + reply_keyboard = [["通过玩家ID", "用过账号ID"], ["退出"]] + await message.reply_markdown_v2( + "请选择你要绑定的方式", reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True) + ) + return CHECK_METHOD - @conversation.state(state=CHECK_UID) - @handler.message(filters=filters.TEXT & ~filters.COMMAND, block=True) - async def check_cookies(self, update: Update, context: CallbackContext) -> int: + @conversation.state(state=CHECK_METHOD) + @handler.message(filters=filters.TEXT & ~filters.COMMAND, block=False) + async def check_method(self, update: Update, _: CallbackContext) -> int: + message = update.effective_message + if message.text == "退出": + await message.reply_text("退出任务", reply_markup=ReplyKeyboardRemove()) + return ConversationHandler.END + if message.text == "通过玩家ID": + await message.reply_text("请输入你的玩家ID(非通行证ID)", reply_markup=ReplyKeyboardRemove()) + return CHECK_PLAYER_ID + if message.text == "用过账号ID": + await message.reply_text("请输入你的通行证ID(非玩家ID)", reply_markup=ReplyKeyboardRemove()) + return CHECK_ACCOUNT_ID + await message.reply_text("选择错误,请重新选择") + return CHECK_METHOD + + @conversation.state(state=CHECK_ACCOUNT_ID) + @handler.message(filters=filters.TEXT & ~filters.COMMAND, block=False) + async def check_account(self, update: Update, context: CallbackContext) -> int: user = update.effective_user message = update.effective_message bind_account_plugin_data: BindAccountPluginData = context.chat_data.get("bind_account_plugin_data") @@ -129,7 +146,7 @@ class BindAccountPlugin(Plugin.Conversation): logger.exception(exc) return ConversationHandler.END if record_card.game != types.Game.GENSHIN: - await message.reply_text("角色信息查询返回非原神游戏信息," "请设置展示主界面为原神", reply_markup=ReplyKeyboardRemove()) + await message.reply_text("角色信息查询返回非原神游戏信息,请设置展示主界面为原神", reply_markup=ReplyKeyboardRemove()) return ConversationHandler.END player_info = await self.players_service.get( user.id, player_id=record_card.uid, region=bind_account_plugin_data.region @@ -148,12 +165,75 @@ class BindAccountPlugin(Plugin.Conversation): f"UID:`{record_card.uid}`\n" f"服务器名称:`{record_card.server_name}`\n" ) - bind_account_plugin_data.record_card = record_card + bind_account_plugin_data.player_id = record_card.uid + bind_account_plugin_data.nickname = record_card.nickname + await message.reply_markdown_v2(text, reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)) + return COMMAND_RESULT + + @conversation.state(state=CHECK_PLAYER_ID) + @handler.message(filters=filters.TEXT & ~filters.COMMAND, block=False) + async def check_player(self, update: Update, context: CallbackContext) -> int: + user = update.effective_user + message = update.effective_message + bind_account_plugin_data: BindAccountPluginData = context.chat_data.get("bind_account_plugin_data") + region = bind_account_plugin_data.region + if message.text == "退出": + await message.reply_text("退出任务", reply_markup=ReplyKeyboardRemove()) + return ConversationHandler.END + try: + player_id = int(message.text) + except ValueError: + await message.reply_text("ID 格式有误,请检查", reply_markup=ReplyKeyboardRemove()) + return ConversationHandler.END + try: + cookies = await self.public_cookies_service.get_cookies(user.id, region) + except TooManyRequestPublicCookies: + await message.reply_text("用户查询次数过多,请稍后重试", reply_markup=ReplyKeyboardRemove()) + return ConversationHandler.END + if region == RegionEnum.HYPERION: + client = genshin.Client(cookies=cookies.data, game=types.Game.GENSHIN, region=types.Region.CHINESE) + elif region == RegionEnum.HOYOLAB: + client = genshin.Client( + cookies=cookies.data, game=types.Game.GENSHIN, region=types.Region.OVERSEAS, lang="zh-cn" + ) + else: + return ConversationHandler.END + try: + player_stats = await client.get_genshin_user(player_id) + except DataNotPublic: + await message.reply_text("角色未公开", reply_markup=ReplyKeyboardRemove()) + logger.warning("获取账号信息发生错误 %s 账户信息未公开", player_id) + return ConversationHandler.END + except GenshinException as exc: + if exc.retcode == 1034: + await message.reply_text("出错了呜呜呜 ~ 请稍后重试") + return ConversationHandler.END + await message.reply_text("获取账号信息发生错误", reply_markup=ReplyKeyboardRemove()) + logger.error("获取账号信息发生错误") + logger.exception(exc) + return ConversationHandler.END + player_info = await self.players_service.get( + user.id, player_id=player_id, region=bind_account_plugin_data.region + ) + if player_info: + await message.reply_text("你已经绑定该账号") + return ConversationHandler.END + reply_keyboard = [["确认", "退出"]] + await message.reply_text("获取角色基础信息成功,请检查是否正确!") + logger.info("用户 %s[%s] 获取账号 %s[%s] 信息成功", user.full_name, user.id, player_stats.info.nickname, player_id) + text = ( + f"*角色信息*\n" + f"角色名称:{escape_markdown(player_stats.info.nickname, version=2)}\n" + f"角色等级:{player_stats.info.level}\n" + f"UID:`{player_id}`\n" + ) + bind_account_plugin_data.player_id = player_id + bind_account_plugin_data.nickname = player_stats.info.nickname await message.reply_markdown_v2(text, reply_markup=ReplyKeyboardMarkup(reply_keyboard, one_time_keyboard=True)) return COMMAND_RESULT @conversation.state(state=COMMAND_RESULT) - @handler.message(filters=filters.TEXT & ~filters.COMMAND, block=True) + @handler.message(filters=filters.TEXT & ~filters.COMMAND, block=False) async def command_result(self, update: Update, context: CallbackContext) -> int: user = update.effective_user message = update.effective_message @@ -162,15 +242,15 @@ class BindAccountPlugin(Plugin.Conversation): await message.reply_text("退出任务", reply_markup=ReplyKeyboardRemove()) return ConversationHandler.END if message.text == "确认": - record_card = bind_account_plugin_data.record_card + player_id = bind_account_plugin_data.player_id + nickname = bind_account_plugin_data.nickname is_chosen = True player_info = await self.players_service.get_player(user.id) # 寻找主账号 if player_info is not None and player_info.is_chosen: is_chosen = False player = Player( user_id=user.id, - account_id=bind_account_plugin_data.account_id, - player_id=record_card.uid, + player_id=player_id, region=bind_account_plugin_data.region, is_chosen=is_chosen, # todo 多账号 ) @@ -180,7 +260,7 @@ class BindAccountPlugin(Plugin.Conversation): player_info = PlayerInfoSQLModel( user_id=player.user_id, player_id=player.player_id, - nickname=record_card.nickname, + nickname=nickname, create_time=datetime.now(), is_update=True, ) # 不添加更新时间