From 2336e159c775aa7dad7ac29fb2a8d310c1dcb4df Mon Sep 17 00:00:00 2001 From: Giovani Date: Fri, 30 Jul 2021 15:19:21 -0400 Subject: [PATCH] feat: add ability to query poll results --- .vscode/launch.json | 15 +++++++++++ cogs/fun.py | 65 ++++++++++++++++++++++++++++++++++++++++----- data/__init__.py | 2 +- pyvis.py | 39 +++++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 7 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..aa0c83d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python: pyvis.py File", + "type": "python", + "request": "launch", + "program": "pyvis.py", + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/cogs/fun.py b/cogs/fun.py index 73a0793..f26ac30 100644 --- a/cogs/fun.py +++ b/cogs/fun.py @@ -1,16 +1,21 @@ +from os import name import random import discord +from discord.ext.commands.core import command import requests import json import requests +from data import poll_cache from datetime import date from discord.ext import commands -OPTION_EMOJIS = ["1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣"] - class Fun(commands.Cog): """Commands that are good for the soul!""" + OPTION_EMOJIS = ["1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣"] + FULL_CHAR = "█" + BAR_LENGTH = 20 + @commands.command() async def flip(self, ctx) -> None: """Flips a coin and return either heads or tails.""" @@ -46,8 +51,14 @@ class Fun(commands.Cog): await ctx.send(embed=github_embed) - @commands.command(usage="\"\" ") - async def poll(self, ctx, *params: str) -> None: + @commands.group(invoke_without_command=True) + async def poll(self, ctx) -> None: + """Allows for creating polls and querying results.""" + await ctx.send("**poll create ->** `!poll create \"My question?\" option1 option2`") + await ctx.send("**poll results ->** `!poll results 870733802190807050`") + + @poll.command(usage="\"\" ", name="create") + async def poll_create(self, ctx, *params: str) -> None: """Creates a poll with the given parameters.""" if len(params) <= 1: @@ -60,9 +71,51 @@ class Fun(commands.Cog): # create embed response poll_embed = discord.Embed(title=question, description="\u200b", color=0x3DCCDD) for i in range(len(options)): - poll_embed.add_field(value="\u200b", name=f"{OPTION_EMOJIS[i]} {options[i]}", inline=False) + poll_embed.add_field(value="\u200b", name=f"{self.OPTION_EMOJIS[i]} {options[i]}", inline=False) poll_embed.set_footer(text=f"Poll created on • {date.today().strftime('%m/%d/%y')}") message = await ctx.send(embed=poll_embed) + + # add poll to cache + poll_cache[message.id] = {} for i in range(len(options)): - await message.add_reaction(OPTION_EMOJIS[i]) \ No newline at end of file + poll_cache[message.id][f"{self.OPTION_EMOJIS[i]}"] = [] + poll_cache[message.id]["question"] = question + poll_cache[message.id]["options"] = ",".join(options) + + # add option emojis to poll + for i in range(len(options)): + await message.add_reaction(self.OPTION_EMOJIS[i]) + + @poll.command(usage="", name="results") + async def poll_results(self, ctx, message_id: int = None) -> None: + """Shows results of a poll given a message id.""" + + if not message_id: + await ctx.send("**Please provide the message id of a poll. ex.** `!poll results 870733802190807050") + return + + if message_id not in poll_cache: + await ctx.send("**Could not find poll with that message id.**") + return + + poll = poll_cache[message_id] + question = poll["question"] + options = poll["options"].split(",") + + total_votes = sum([0 if item[0] == "question" or item[0] == "options" else len(item[1]) for item in poll.items()]) + option_percentages = [] + for i in range(len(options)): + option_votes = len(poll[self.OPTION_EMOJIS[i]]) + option_percentages.append(0 if total_votes == 0 else option_votes / total_votes) + + # construct embed response + results_embed = discord.Embed(title=question, description="🥁", color=0x3DCCDD) + for i in range(len(options)): + str_bar = "".join([self.FULL_CHAR for _ in range(int(self.BAR_LENGTH * option_percentages[i]))]) + str_percent = f"{option_percentages[i] * 100:.2f}%" + str_votes = f"({int(option_percentages[i] * total_votes)} votes)" + results_embed.add_field(name=f"{self.OPTION_EMOJIS[i]} {options[i]}", value=f"{str_bar} {str_percent} {str_votes}", inline=False) + results_embed.set_footer(text=f"Poll queried on • {date.today().strftime('%m/%d/%y')}") + + await ctx.send(embed=results_embed) diff --git a/data/__init__.py b/data/__init__.py index f0be901..c091082 100644 --- a/data/__init__.py +++ b/data/__init__.py @@ -1 +1 @@ -DUMMY_CACHE = {} \ No newline at end of file +poll_cache = {} # TODO: use a real cache \ No newline at end of file diff --git a/pyvis.py b/pyvis.py index ccdebc1..bdd852e 100644 --- a/pyvis.py +++ b/pyvis.py @@ -1,11 +1,13 @@ import discord import os +from discord.flags import MessageFlags import requests import json import random from cogs import Programming from cogs import Fun from cogs import Finance +from data import poll_cache from discord.ext import commands from dotenv import load_dotenv from pretty_help import DefaultMenu, PrettyHelp @@ -20,6 +22,7 @@ PREFIX = "!" intents = discord.Intents.default() intents.members = True +intents.reactions = True bot = commands.Bot(command_prefix=PREFIX, intents=intents) @bot.event @@ -33,6 +36,7 @@ async def on_ready(): @bot.event async def on_member_join(member): + """ WELCOME START """ guild = discord.utils.find(lambda g: g.name == DISCORD_GUILD_NAME, bot.guilds) # TODO: check if find will throw an error welcome_channel = discord.utils.find(lambda c: c.name == "👋welcome", guild.channels) # TODO: remove welcome channel hardcode @@ -45,6 +49,7 @@ async def on_member_join(member): await welcome_channel.send(embed=gif_embed) await welcome_channel.send(f"<@!{member.id}> **Welcome to {DISCORD_GUILD_NAME}!** :wave:") + """ WELCOME END """ @bot.event async def on_message(message): @@ -52,6 +57,8 @@ async def on_message(message): if message.author == bot.user: return + # TODO: is channel is a proposal channel check for poll command + # repsond with command prefix if bot.user.mentioned_in(message) and not message.mention_everyone: await message.channel.send(f"**Learn more about me by running:** `{PREFIX}help`") @@ -59,6 +66,38 @@ async def on_message(message): # allow cogs to handle messages too await bot.process_commands(message) +@bot.event +async def on_raw_reaction_add(event): + # avoid bot self trigger + if event.user_id == bot.user.id: + return + + """ POLL START """ + # check if message is in cache and if reaction is valid + if event.message_id in poll_cache and event.emoji.name in Fun.OPTION_EMOJIS: + # if user has not voted yet, add their vote + if event.user_id not in poll_cache[event.message_id][event.emoji.name]: + poll_cache[event.message_id][event.emoji.name].append(event.user_id) + """ POLL END """ + + print(poll_cache) + +@bot.event +async def on_raw_reaction_remove(event): + # avoid bot self trigger + if event.user_id == bot.user.id: + return + + """ POLL START """ + # check if message is in cache and if reaction is valid + if event.message_id in poll_cache and event.emoji.name in Fun.OPTION_EMOJIS: + # if user has voted, remove their vote + if event.user_id in poll_cache[event.message_id][event.emoji.name]: + poll_cache[event.message_id][event.emoji.name].remove(event.user_id) + """ POLL END """ + + print(poll_cache) + # override default help command menu = DefaultMenu('◀️', '▶️', '❌') bot.help_command = PrettyHelp(navigation=menu, color=discord.Colour.green())