diff --git a/bot/cogs/admin.py b/bot/cogs/admin.py index 52697f7..999cc41 100644 --- a/bot/cogs/admin.py +++ b/bot/cogs/admin.py @@ -592,7 +592,10 @@ async def sync(self, ctx: Context): await ctx.send("Slash commands sincronizados com sucesso.") @app_commands.check(is_pedim_or_nriver) - @app_commands.command(name="atl-spam", description="Envia uma mensagem no privado para todos os membros do servidor") + @app_commands.command( + name="atl-spam", + description="Envia uma mensagem no privado para todos os membros do servidor", + ) async def atl_spam( self, interaction: discord.Interaction, diff --git a/bot/cogs/authentication.py b/bot/cogs/authentication.py index bfe680d..28a82af 100644 --- a/bot/cogs/authentication.py +++ b/bot/cogs/authentication.py @@ -262,6 +262,49 @@ def settings_embed(settings: dict): return embed +class _IngameNameModal(discord.ui.Modal, title="Autenticação - Nome no Jogo"): + ingame_name = discord.ui.TextInput( + label="Nome no jogo (RuneScape 3)", + placeholder="Ex: Zezinho 123", + min_length=1, + max_length=12, + ) + + def __init__(self): + super().__init__(timeout=300) + self.interaction: Optional[discord.Interaction] = None + + async def on_submit(self, interaction: discord.Interaction): + self.interaction = interaction + self.stop() + + +class _ConfirmView(discord.ui.View): + def __init__(self, author_id: int, label: str = "Confirmar", *, timeout: float = 180): + super().__init__(timeout=timeout) + self.author_id = author_id + self.interaction: Optional[discord.Interaction] = None + for item in self.children: + if isinstance(item, discord.ui.Button): + item.label = label + break + + @discord.ui.button(label="Confirmar", style=discord.ButtonStyle.green, emoji="✅") + async def confirm(self, interaction: discord.Interaction, button: discord.ui.Button): + if interaction.user.id != self.author_id: + await interaction.response.send_message( + "Este botão não é para você.", ephemeral=True + ) + return + self.interaction = interaction + button.disabled = True + await interaction.response.edit_message(view=self) + self.stop() + + async def on_timeout(self): + self.stop() + + class UserAuthentication(commands.Cog): def __init__(self, bot: Bot): self.bot = bot @@ -716,44 +759,53 @@ async def aplicar_role(self, ctx: Context): "Você agora é um Membro do clã autenticado no Discord." ) - def check(message: discord.Message): - return message.author == ctx.author - - await ctx.send(f"{ctx.author.mention}, por favor me diga o seu nome no jogo.") - - try: - ingame_name = await self.bot.wait_for("message", timeout=180.0, check=check) - except asyncio.TimeoutError: - self.logger.info( - f"[{ctx.author}] Autenticação cancelada por Timeout (ingame_name)." - ) - return await ctx.send( - f"{ctx.author.mention}, autenticação cancelada. Tempo Esgotado." - ) + if ctx.interaction: + modal = _IngameNameModal() + await ctx.interaction.response.send_modal(modal) + await modal.wait() + if not modal.interaction: + self.logger.info( + f"[{ctx.author}] Autenticação cancelada por Timeout (ingame_name)." + ) + return + await modal.interaction.response.defer() + ingame_name_str = modal.ingame_name.value.strip() + else: + await ctx.send(f"{ctx.author.mention}, por favor me diga o seu nome no jogo.") + try: + ingame_name_msg = await self.bot.wait_for( + "message", timeout=180.0, check=lambda m: m.author == ctx.author + ) + except asyncio.TimeoutError: + self.logger.info( + f"[{ctx.author}] Autenticação cancelada por Timeout (ingame_name)." + ) + return await ctx.send( + f"{ctx.author.mention}, autenticação cancelada. Tempo Esgotado." + ) + ingame_name_str = ingame_name_msg.content.strip() - if len(ingame_name.content.strip()) > 12: + if len(ingame_name_str) > 12: return await ctx.send("Nome Inválido. Tamanho muito grande.") # Já existe outro usuário cadastrado com esse username in-game user_ingame = DiscordUser.objects.filter( - ~Q(discord_id=str(ctx.author.id)), ingame_name__iexact=ingame_name.content + ~Q(discord_id=str(ctx.author.id)), ingame_name__iexact=ingame_name_str ).first() + account_switch = False if user_ingame: self.logger.info( - f"[{ctx.author}] já existe usuário in-game autenticado com esse nome. ({user_ingame})" - ) - return await ctx.send( - "Já existe um Usuário do Discord autenticado com esse nome do jogo.\n" - "Caso seja mesmo o Dono dessa conta e acredite que outra pessoa tenha se cadastrado " - "com o seu nome por favor me contate aqui: <@148175892596785152>." + f"[{ctx.author}] já existe usuário in-game autenticado com esse nome, " + f"permitindo account switch. ({user_ingame})" ) + account_switch = True async with aiohttp.ClientSession() as cs: - user_data = await get_user_data(ingame_name.content, cs) + user_data = await get_user_data(ingame_name_str, cs) if not user_data: self.logger.info( - f"[{ctx.author}] Erro acessando API do RuneScape. ({ingame_name.content})" + f"[{ctx.author}] Erro acessando API do RuneScape. ({ingame_name_str})" ) return await ctx.send( "Houve um erro ao tentar acessar a API do RuneScape. Tente novamente mais tarde." @@ -807,6 +859,8 @@ def check(message: discord.Message): worlds_requirement = random.randint(2, 3) if re_auth: worlds_requirement = 2 + if account_switch: + worlds_requirement += 3 if player_world["language"] == "pt" else 2 settings = { "f2p_worlds": player_world["f2p"], @@ -816,19 +870,13 @@ def check(message: discord.Message): "failed_tries": 0, } - def confirm_check(reaction, user): - return user == ctx.author and str(reaction.emoji) == "✅" - settings_message = await ctx.send(embed=settings_embed(settings)) + ready_view = _ConfirmView(ctx.author.id, "Estou pronto", timeout=180) confirm_message = await ctx.send( - "Reaja nessa mensagem quando estiver pronto." + "Clique no botão quando estiver pronto para começar:", view=ready_view ) - await confirm_message.add_reaction("✅") - try: - await self.bot.wait_for( - "reaction_add", timeout=180, check=confirm_check - ) - except asyncio.TimeoutError: + await ready_view.wait() + if ready_view.interaction is None: self.logger.info( f"[{ctx.author}] Autenticação cancelada por Timeout. ({user_data})" ) @@ -855,18 +903,15 @@ def confirm_check(reaction, user): last_world = world + hop_view = _ConfirmView(ctx.author.id, "Já estou neste mundo", timeout=160) message: discord.Message = await ctx.send( f"{ctx.author.mention}, troque para o **Mundo {world['world']}**. " - f"Reaja na mensagem quando estiver nele." + f"Clique no botão quando estiver nele.", + view=hop_view, ) - await message.add_reaction("✅") - - try: - await self.bot.wait_for( - "reaction_add", timeout=160, check=confirm_check - ) - except asyncio.TimeoutError: + await hop_view.wait() + if hop_view.interaction is None: self.logger.info( f"[{ctx.author}] Autenticação cancelada por Timeout. (mundo) ({settings}) ({user_data})" ) @@ -1088,6 +1133,14 @@ def confirm_check(reaction, user): await auth_chat.send(embed=confirm_embed) + if account_switch and user_ingame: + user_ingame.disabled = True + user_ingame.warning_date = None + user_ingame.save() + self.logger.info( + f"[{ctx.author}] Conta anterior desabilitada após account switch. ({user_ingame})" + ) + self.logger.info(f"[{ctx.author}] Autenticação finalizada.") await ctx.send(embed=self.feedback_embed()) diff --git a/bot/cogs/teams.py b/bot/cogs/teams.py index 190077c..a7069ae 100644 --- a/bot/cogs/teams.py +++ b/bot/cogs/teams.py @@ -437,7 +437,7 @@ def role_check(message): else: field["value"] = answer.content - if type(field["value"]) == str and field["value"].lower() == "nenhum": + if isinstance(field["value"], str) and field["value"].lower() == "nenhum": field["value"] = None elif field["name"] == "role" or field["name"] == "role_secondary": field["value"] = re.search(r"\d+", answer.content).group()