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
|
#!/usr/bin/env python3
|
||||||
import argparse
|
import argparse
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import Dict, Tuple, Coroutine
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
import discord.utils
|
import discord.utils
|
||||||
|
|
@ -21,11 +23,14 @@ class SecretBot(commands.Cog):
|
||||||
self.bot = commands.Bot(
|
self.bot = commands.Bot(
|
||||||
"!",
|
"!",
|
||||||
help_command = commands.MinimalHelpCommand(),
|
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
|
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.bot.add_cog(self)
|
||||||
self.games_file = games_file
|
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):
|
def run(self, token):
|
||||||
self.bot.run(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!")
|
await ctx.reply(":warning: You should do this in the admin channel!")
|
||||||
raise utils.CheckFailDoNotNotify
|
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")
|
@commands.command(help = "See if I'm alive")
|
||||||
async def ping(self, ctx: commands.Context):
|
async def ping(self, ctx: commands.Context):
|
||||||
await ctx.reply(":ping_pong:", mention_author = True)
|
await ctx.reply(":ping_pong:", mention_author = True)
|
||||||
|
|
@ -130,9 +183,13 @@ class SecretBot(commands.Cog):
|
||||||
await ctx.reply(":white_check_mark: Game started!")
|
await ctx.reply(":white_check_mark: Game started!")
|
||||||
|
|
||||||
@commands.command("DeleteGame", help = "Delete a running game and all of its associated channels")
|
@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):
|
async def delete_game(self, ctx: commands.Context):
|
||||||
game = await self.get_running_game_or_error_message(ctx)
|
game = await self.get_running_game_or_error_message(ctx)
|
||||||
await self.check_is_administrator_or_gm(ctx)
|
|
||||||
gm_role = game.get_gm_role()
|
gm_role = game.get_gm_role()
|
||||||
await game.delete()
|
await game.delete()
|
||||||
await ctx.guild.get_member(self.bot.user.id).remove_roles(gm_role)
|
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)
|
await self.cast_vote(ctx, False)
|
||||||
|
|
||||||
@commands.command("StopTheCount")
|
@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)
|
game = await self.get_running_game_or_error_message(ctx)
|
||||||
await self.check_is_administrator_or_gm(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():
|
if not game.is_vote_running():
|
||||||
await ctx.reply(":x: No vote is running")
|
await ctx.reply(":x: No vote is running")
|
||||||
return
|
return
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue