Added possibility to confirm some actions
This commit is contained in:
parent
15945d839c
commit
03cee9963b
70
SecretBot.py
70
SecretBot.py
|
|
@ -1,8 +1,10 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import asyncio
|
||||
import logging
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Dict, Tuple, Coroutine
|
||||
|
||||
import discord
|
||||
import discord.utils
|
||||
|
|
@ -21,11 +23,14 @@ class SecretBot(commands.Cog):
|
|||
self.bot = commands.Bot(
|
||||
"!",
|
||||
help_command = commands.MinimalHelpCommand(),
|
||||
intents = discord.Intents(guild_messages = True, guilds = True, members = True),
|
||||
intents = discord.Intents(guild_messages = True, guilds = True, members = True, reactions = True),
|
||||
allowed_mentions = discord.AllowedMentions.none(), # By default we do not allow mentions, as we will white-list them on each required message
|
||||
)
|
||||
self.bot.add_cog(self)
|
||||
self.games_file = games_file
|
||||
# Each guild can have a confirmation message to execute an action. We store:
|
||||
# The confirmation message, the coroutine to execute if the user reacts with :thumbsup: to the confirmation message, a task that will delete the message after a certain time (so that we can stop it if the user confirms instead)
|
||||
self.confirmation_messages: Dict[discord.guild, Tuple[discord.Message, Coroutine, asyncio.Task]] = {}
|
||||
|
||||
def run(self, token):
|
||||
self.bot.run(token)
|
||||
|
|
@ -114,6 +119,54 @@ class SecretBot(commands.Cog):
|
|||
await ctx.reply(":warning: You should do this in the admin channel!")
|
||||
raise utils.CheckFailDoNotNotify
|
||||
|
||||
async def confirm_action(self, message_text, text_channel: discord.TextChannel, action: Coroutine, reply_to: discord.Message = None, max_delay = 60):
|
||||
"""
|
||||
Asks the user to confirm an action by reacting to a message.
|
||||
If the user does not react in max_delay seconds, the confirmation message is deleted and the action is canceled.
|
||||
For now, only one such confirmation per server is allowed. If another confirmation is asked while a previous one exists, the previous one is treated as if the delay passed.
|
||||
"""
|
||||
if text_channel.guild in self.confirmation_messages: # If there was already a pending confirmation
|
||||
# We delete it
|
||||
message, action, task = self.confirmation_messages[text_channel.guild]
|
||||
asyncio.create_task(message.delete())
|
||||
action.close()
|
||||
task.cancel()
|
||||
|
||||
message = await text_channel.send(message_text + "\nReact to this message with :thumbsup: to confirm or :thumbsdown: to cancel", reference = reply_to)
|
||||
|
||||
async def add_reaction_prompts():
|
||||
await message.add_reaction("👍")
|
||||
await message.add_reaction("👎")
|
||||
asyncio.create_task(add_reaction_prompts())
|
||||
|
||||
async def delete_confirmation_message_after_max_delay():
|
||||
await asyncio.sleep(max_delay)
|
||||
del self.confirmation_messages[text_channel.guild]
|
||||
action.close()
|
||||
await message.delete()
|
||||
|
||||
self.confirmation_messages[text_channel.guild] = (message, action, asyncio.create_task(delete_confirmation_message_after_max_delay()))
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_reaction_add(self, reaction: discord.Reaction, user: discord.Member):
|
||||
if user.bot: # We ignore reactions added by bots
|
||||
return
|
||||
if reaction.message.guild in self.confirmation_messages:
|
||||
message, action, task = self.confirmation_messages[reaction.message.guild]
|
||||
if reaction.message == message:
|
||||
# Note that we do not check which user added the reaction.
|
||||
# The confirmation message is just supposed to be a safeguard against typing mistakes
|
||||
if reaction.emoji == "👍":
|
||||
del self.confirmation_messages[reaction.message.guild]
|
||||
task.cancel()
|
||||
asyncio.create_task(message.delete())
|
||||
await action
|
||||
elif reaction.emoji == "👎":
|
||||
del self.confirmation_messages[reaction.message.guild]
|
||||
task.cancel()
|
||||
action.close()
|
||||
await message.delete()
|
||||
|
||||
@commands.command(help = "See if I'm alive")
|
||||
async def ping(self, ctx: commands.Context):
|
||||
await ctx.reply(":ping_pong:", mention_author = True)
|
||||
|
|
@ -130,9 +183,13 @@ class SecretBot(commands.Cog):
|
|||
await ctx.reply(":white_check_mark: Game started!")
|
||||
|
||||
@commands.command("DeleteGame", help = "Delete a running game and all of its associated channels")
|
||||
async def delete_game_with_confirmation(self, ctx: commands.Context):
|
||||
await self.get_running_game_or_error_message(ctx)
|
||||
await self.check_is_administrator_or_gm(ctx)
|
||||
await self.confirm_action("Do you really want to delete the current game?", ctx.channel, self.delete_game(ctx), ctx.message)
|
||||
|
||||
async def delete_game(self, ctx: commands.Context):
|
||||
game = await self.get_running_game_or_error_message(ctx)
|
||||
await self.check_is_administrator_or_gm(ctx)
|
||||
gm_role = game.get_gm_role()
|
||||
await game.delete()
|
||||
await ctx.guild.get_member(self.bot.user.id).remove_roles(gm_role)
|
||||
|
|
@ -174,9 +231,16 @@ class SecretBot(commands.Cog):
|
|||
await self.cast_vote(ctx, False)
|
||||
|
||||
@commands.command("StopTheCount")
|
||||
async def stop_vote(self, ctx: commands.Context):
|
||||
async def stop_vote_with_confirmation(self, ctx: commands.Context):
|
||||
game = await self.get_running_game_or_error_message(ctx)
|
||||
await self.check_is_administrator_or_gm(ctx)
|
||||
if not game.is_vote_running():
|
||||
await ctx.reply(":x: No vote is running")
|
||||
return
|
||||
await self.confirm_action("Do you really want to stop the vote and reveal all votes?", ctx.channel, self.stop_vote(ctx), ctx.message)
|
||||
|
||||
async def stop_vote(self, ctx: commands.Context):
|
||||
game = await self.get_running_game_or_error_message(ctx)
|
||||
if not game.is_vote_running():
|
||||
await ctx.reply(":x: No vote is running")
|
||||
return
|
||||
|
|
|
|||
Loading…
Reference in New Issue