Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add poll and survey bot for Discord #19

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 26 additions & 0 deletions poll_and_survey_bot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Poll and Survey Bot for Discord

This Discord bot allows users to create and participate in polls and surveys with various question types, such as multiple-choice, rating scales, and open-ended questions. The results are collected and displayed in an easy-to-understand format.

## Features

- Create polls and surveys with various question types.
- Participate in polls and surveys by reacting to messages or submitting responses through text.
- View poll and survey results in an organized and easy-to-understand format.
- Customize the appearance of poll and survey messages.

## Setup

1. Clone this repository or download the `poll_and_survey_bot` folder.
2. Install the required packages by running `pip install -r requirements.txt`.
3. Create a new Discord bot and obtain its token. To do this, follow the instructions in the [Discord Developer Portal](https://discord.com/developers/applications).
4. Rename `config_example.json` to `config.json` and insert your bot token and desired prefix.
5. Run the bot by executing `python bot.py`.

## Usage Instructions

- To create a poll, use the command `!poll <title> <option1> <option2> ... <optionN>`. For example, `!poll "Favorite Fruit" Apple Banana Orange`.
- To create a survey, use the command `!survey <title>`. The bot will DM you with instructions on how to add questions and publish the survey.
- To view the results of a poll or survey, use the command `!results <poll/survey ID>`.

For more detailed instructions and additional commands, type `!help` in a channel where the bot is present.
62 changes: 62 additions & 0 deletions poll_and_survey_bot/bot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import discord
from discord.ext import commands
from poll import Poll
from utils import parse_poll_args

intents = discord.Intents.default()
intents.typing = False
intents.presences = False

bot = commands.Bot(command_prefix='!', intents=intents)

@bot.event
async def on_ready():
print(f'We have logged in as {bot.user}')

@bot.command()
async def create_poll(ctx, *args):
poll_args = parse_poll_args(args)

if poll_args is None:
await ctx.send('Invalid poll arguments. Please use the correct format: `!create_poll "Question" "Option 1" "Option 2" ...`')
return

question, options = poll_args
poll = Poll(question, options)

embed = discord.Embed(title=question, description='\n'.join([f'{i+1}. {opt}' for i, opt in enumerate(options)]))

message = await ctx.send(embed=embed)

for i in range(len(options)):
await message.add_reaction(str(i + 1) + '\N{COMBINING ENCLOSING KEYCAP}')

poll.set_message_id(message.id)
poll.set_author_id(ctx.author.id)

@bot.command()
async def close_poll(ctx, message_id: int):
# Retrieve the poll associated with the message ID and close it

try:
poll = Poll.get_poll_by_message_id(message_id)
except ValueError:
await ctx.send('Invalid message ID.')
return

if poll is None:
await ctx.send('No poll found with that message ID.')
return

if poll.author_id != ctx.author.id:
await ctx.send('You do not have permission to close this poll.')
return

poll.close()

embed = discord.Embed(title=poll.question, description='\n'.join([f'{i+1}. {opt}' for i, opt in enumerate(poll.options)]))
embed.add_field(name='Results', value=poll.get_results())

await ctx.send(embed=embed)

bot.run('your-bot-token')
61 changes: 61 additions & 0 deletions poll_and_survey_bot/survey.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from dataclasses import dataclass
from typing import List
from enum import Enum

class QuestionType(Enum):
MULTIPLE_CHOICE = "multiple_choice"
RATING_SCALE = "rating_scale"
OPEN_ENDED = "open_ended"

@dataclass(frozen=True)
class Question:
question_type: QuestionType
text: str
options: List[str] = None
scale: int = None

class Survey:
def __init__(self, title: str):
self.title = title
self.questions = []
self.responses = []

def add_question(self, question_type: QuestionType, text: str, options=None, scale=None):
question = Question(question_type=question_type, text=text, options=options, scale=scale)
self.questions.append(question)

def submit_response(self, response: List):
if len(response) != len(self.questions):
raise ValueError("Invalid response length")
self.responses.append(response)

def get_results(self):
results = {}
for i, question in enumerate(self.questions):
if question.question_type == QuestionType.MULTIPLE_CHOICE:
results[question.text] = self._get_multiple_choice_results(i)
elif question.question_type == QuestionType.RATING_SCALE:
results[question.text] = self._get_rating_scale_results(i)
elif question.question_type == QuestionType.OPEN_ENDED:
results[question.text] = self._get_open_ended_responses(i)
return results

def _get_multiple_choice_results(self, question_index: int):
results = {}
for response in self.responses:
answer = response[question_index]
if answer in results:
results[answer] += 1
else:
results[answer] = 1
return results

def _get_rating_scale_results(self, question_index: int):
results = [0] * (self.questions[question_index].scale + 1)
for response in self.responses:
answer = response[question_index]
results[answer] += 1
return results

def _get_open_ended_responses(self, question_index: int):
return [response[question_index] for response in self.responses]