From 0b653274546a5722935ee67dd49247f5d1375f02 Mon Sep 17 00:00:00 2001 From: flifloo Date: Fri, 10 Apr 2020 20:37:14 +0200 Subject: [PATCH 1/6] Add poll command --- extensions/__init__.py | 1 + extensions/poll.py | 112 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+) create mode 100644 extensions/poll.py diff --git a/extensions/__init__.py b/extensions/__init__.py index 9953568..4e0e6ec 100644 --- a/extensions/__init__.py +++ b/extensions/__init__.py @@ -4,3 +4,4 @@ bot.load_extension("extensions.help") bot.load_extension("extensions.speak") bot.load_extension("extensions.extension") bot.load_extension("extensions.purge") +bot.load_extension("extensions.poll") diff --git a/extensions/poll.py b/extensions/poll.py new file mode 100644 index 0000000..1d8b5b3 --- /dev/null +++ b/extensions/poll.py @@ -0,0 +1,112 @@ +from discord.ext import commands +from discord import Member, Embed, Reaction +from discord.ext.commands import CommandNotFound, MissingRequiredArgument + +from bot_bde.logger import logger + + +extension_name = "poll" +logger = logger.getChild(extension_name) +REACTIONS = [] +for i in range(10): + REACTIONS.append(str(i)+"\ufe0f\u20E3") +REACTIONS.append("\U0001F51F") + + +class Poll(commands.Cog): + def __init__(self, bot: commands.Bot): + self.bot = bot + self.polls = {} + + @commands.group("poll", pass_context=True) + @commands.guild_only() + async def poll(self, ctx: commands.Context, name: str, *choices): + if ctx.invoked_subcommand is None: + multi = False + if choices and choices[0] in ["multi", "m"]: + multi = True + choices = choices[1:] + if len(choices) == 0 or len(choices) > 11: + await ctx.message.add_reaction("\u274C") + else: + embed = Embed(title=name) + for i, choice in enumerate(choices): + embed.add_field(name=REACTIONS[i], value=choice, inline=False) + message = await ctx.send(embed=embed) + reactions = REACTIONS[0:len(choices)] + ["\U0001F5D1"] + for reaction in reactions: + await message.add_reaction(reaction) + message = await message.channel.fetch_message(message.id) + self.polls[message.id] = {"multi": multi, "message": message, "author": ctx.message.author.id} + + @poll.group("help", pass_context=True) + @commands.guild_only() + async def speak_help(self, ctx: commands.Context): + embed = Embed(title="poll help") + embed.add_field(name="poll ", + value="...", inline=False) + await ctx.send(embed=embed) + + @commands.Cog.listener() + async def on_reaction_add(self, reaction: Reaction, user: Member): + if not user.bot and reaction.message.id in self.polls: + if reaction not in self.polls[reaction.message.id]["message"].reactions: + await reaction.remove(user) + elif str(reaction.emoji) == "\U0001F5D1": + if user.id != self.polls[reaction.message.id]["author"]: + await reaction.remove(user) + else: + await self.close_poll(reaction.message.id) + elif not self.polls[reaction.message.id]["multi"]: + f = False + for r in reaction.message.reactions: + if str(r.emoji) != str(reaction.emoji): + async for u in r.users(): + if u == user: + await r.remove(user) + f = True + break + if f: + break + + async def close_poll(self, id: int): + message = await self.polls[id]["message"].channel.fetch_message(id) + embed = message.embeds[0] + for i, f in enumerate(embed.fields): + embed.set_field_at(i, name=f"{f.name} - {message.reactions[i].count-1}", value=f.value, inline=False) + await message.clear_reactions() + await message.edit(embed=embed) + + @commands.Cog.listener() + async def on_command_error(self, ctx: commands.Context, error): + if ctx.invoked_with == extension_name or \ + (ctx.command.root_parent is not None and ctx.command.root_parent.name == extension_name): + if isinstance(error, CommandNotFound): + await ctx.message.add_reaction("\u2753") + await ctx.message.delete(delay=30) + if isinstance(error, MissingRequiredArgument): + await ctx.message.add_reaction("\u274C") + await ctx.message.delete(delay=30) + else: + await ctx.send("An error occurred !") + raise error + + +def setup(bot): + logger.info(f"Loading...") + try: + bot.add_cog(Poll(bot)) + except Exception as e: + logger.error(f"Error loading: {e}") + else: + logger.info(f"Load successful") + + +def teardown(bot): + logger.info(f"Unloading...") + try: + bot.remove_cog("Poll") + except Exception as e: + logger.error(f"Error unloading: {e}") + else: + logger.info(f"Unload successful") From b1f37c2ecf0e3d68bedae5c418bfae948877d6b6 Mon Sep 17 00:00:00 2001 From: flifloo Date: Fri, 10 Apr 2020 20:39:09 +0200 Subject: [PATCH 2/6] Remove command message --- extensions/poll.py | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/poll.py b/extensions/poll.py index 1d8b5b3..abfb792 100644 --- a/extensions/poll.py +++ b/extensions/poll.py @@ -38,6 +38,7 @@ class Poll(commands.Cog): await message.add_reaction(reaction) message = await message.channel.fetch_message(message.id) self.polls[message.id] = {"multi": multi, "message": message, "author": ctx.message.author.id} + await ctx.message.delete() @poll.group("help", pass_context=True) @commands.guild_only() From fa90f7c4afcb5126b0f0a9f8fa65c8ff22242701 Mon Sep 17 00:00:00 2001 From: flifloo Date: Fri, 10 Apr 2020 20:41:58 +0200 Subject: [PATCH 3/6] Faster clean reaction to avoid count loss --- extensions/poll.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions/poll.py b/extensions/poll.py index abfb792..0777487 100644 --- a/extensions/poll.py +++ b/extensions/poll.py @@ -72,10 +72,11 @@ class Poll(commands.Cog): async def close_poll(self, id: int): message = await self.polls[id]["message"].channel.fetch_message(id) + reactions = message.reactions + await message.clear_reactions() embed = message.embeds[0] for i, f in enumerate(embed.fields): - embed.set_field_at(i, name=f"{f.name} - {message.reactions[i].count-1}", value=f.value, inline=False) - await message.clear_reactions() + embed.set_field_at(i, name=f"{f.name} - {reactions[i].count-1}", value=f.value, inline=False) await message.edit(embed=embed) @commands.Cog.listener() From cef527c81d9bbce64ebbebd058d9e9da502303d9 Mon Sep 17 00:00:00 2001 From: flifloo Date: Fri, 10 Apr 2020 20:43:03 +0200 Subject: [PATCH 4/6] Forget to remove poll from list :/ --- extensions/poll.py | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/poll.py b/extensions/poll.py index 0777487..410fc6b 100644 --- a/extensions/poll.py +++ b/extensions/poll.py @@ -78,6 +78,7 @@ class Poll(commands.Cog): for i, f in enumerate(embed.fields): embed.set_field_at(i, name=f"{f.name} - {reactions[i].count-1}", value=f.value, inline=False) await message.edit(embed=embed) + del self.polls[id] @commands.Cog.listener() async def on_command_error(self, ctx: commands.Context, error): From bf11ecb7e347389f98218e1dd2f5c3c3f80f2d4c Mon Sep 17 00:00:00 2001 From: flifloo Date: Fri, 10 Apr 2020 20:54:46 +0200 Subject: [PATCH 5/6] Add author on embed, creation and close date and time --- extensions/poll.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/extensions/poll.py b/extensions/poll.py index 410fc6b..4a6b1d6 100644 --- a/extensions/poll.py +++ b/extensions/poll.py @@ -1,3 +1,5 @@ +from datetime import datetime + from discord.ext import commands from discord import Member, Embed, Reaction from discord.ext.commands import CommandNotFound, MissingRequiredArgument @@ -29,7 +31,9 @@ class Poll(commands.Cog): if len(choices) == 0 or len(choices) > 11: await ctx.message.add_reaction("\u274C") else: - embed = Embed(title=name) + embed = Embed(title=f"Poll: {name}") + embed.set_author(name=str(ctx.author), icon_url=ctx.author.avatar_url) + embed.set_footer(text=f"Created: {ctx.message.created_at.strftime('%d/%m/%Y %H:%M')}") for i, choice in enumerate(choices): embed.add_field(name=REACTIONS[i], value=choice, inline=False) message = await ctx.send(embed=embed) @@ -71,12 +75,14 @@ class Poll(commands.Cog): break async def close_poll(self, id: int): + time = datetime.now() message = await self.polls[id]["message"].channel.fetch_message(id) reactions = message.reactions await message.clear_reactions() embed = message.embeds[0] for i, f in enumerate(embed.fields): embed.set_field_at(i, name=f"{f.name} - {reactions[i].count-1}", value=f.value, inline=False) + embed.set_footer(text=embed.footer.text + "\n" + f"Close: {time.strftime('%d/%m/%Y %H:%M')}") await message.edit(embed=embed) del self.polls[id] From f4017fc764b57c5f57081730bb5453af9bcf99b6 Mon Sep 17 00:00:00 2001 From: flifloo Date: Fri, 10 Apr 2020 21:02:06 +0200 Subject: [PATCH 6/6] Add some help --- extensions/poll.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/extensions/poll.py b/extensions/poll.py index 4a6b1d6..2563f2c 100644 --- a/extensions/poll.py +++ b/extensions/poll.py @@ -23,7 +23,9 @@ class Poll(commands.Cog): @commands.group("poll", pass_context=True) @commands.guild_only() async def poll(self, ctx: commands.Context, name: str, *choices): - if ctx.invoked_subcommand is None: + if name == "help": + await ctx.invoke(self.poll_help) + else: multi = False if choices and choices[0] in ["multi", "m"]: multi = True @@ -46,10 +48,12 @@ class Poll(commands.Cog): @poll.group("help", pass_context=True) @commands.guild_only() - async def speak_help(self, ctx: commands.Context): + async def poll_help(self, ctx: commands.Context): embed = Embed(title="poll help") - embed.add_field(name="poll ", - value="...", inline=False) + embed.add_field(name="poll [multi|m] ... ", + value="Create a poll, the argument multi (or m) after the name allow multiple response\n" + "User the \U0001F5D1 to close the poll", + inline=False) await ctx.send(embed=embed) @commands.Cog.listener()