working on 2.4
mention command started with debug command export for custom votes finished cmd
This commit is contained in:
parent
c2633240c1
commit
99898c9a14
44
cogs/help.py
44
cogs/help.py
@ -51,7 +51,7 @@ class Help(commands.Cog):
|
||||
if page == '🏠':
|
||||
## POLL CREATION SHORT
|
||||
embed.add_field(name='🆕 Making New Polls',
|
||||
value=f'`{pre}quick` | `{pre}new` | `{pre}prepare` | `{pre}cmd <args>`', inline=False)
|
||||
value=f'`{pre}quick` | `{pre}new` | `{pre}advanced` | `{pre}prepare` | `{pre}cmd <args>`', inline=False)
|
||||
# embed.add_field(name='Commands', value=f'`{pre}quick` | `{pre}new` | `{pre}prepared`', inline=False)
|
||||
# embed.add_field(name='Arguments', value=f'Arguments: `<poll question>` (optional)', inline=False)
|
||||
# embed.add_field(name='Examples', value=f'Examples: `{pre}new` | `{pre}quick What is the greenest color?`',
|
||||
@ -221,6 +221,48 @@ class Help(commands.Cog):
|
||||
# cleanup
|
||||
await ctx.message.delete()
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
if message.content.startswith("@mention "):
|
||||
channel = message.channel
|
||||
if not isinstance(channel, discord.TextChannel):
|
||||
await channel.send("@mention can only be used in a server text channel.")
|
||||
return
|
||||
|
||||
guild = message.guild
|
||||
if not guild:
|
||||
await channel.send("Could not determine your server.")
|
||||
return
|
||||
|
||||
tag = message.content.split()[1].lower()
|
||||
if tag == "prefix":
|
||||
pre = await get_server_pre(self.bot, guild)
|
||||
# await channel.send(f'The prefix for this server/channel is: \n {pre} \n To change it type: \n'
|
||||
# f'{pre}prefix <new_prefix>')
|
||||
await channel.send(pre)
|
||||
|
||||
elif message.content == "@debug":
|
||||
channel = message.channel
|
||||
if not isinstance(channel, discord.TextChannel):
|
||||
await channel.send("@debug can only be used in a server text channel.")
|
||||
return
|
||||
|
||||
guild = message.guild
|
||||
if not guild:
|
||||
await channel.send("Could not determine your server.")
|
||||
return
|
||||
|
||||
status_msg = ''
|
||||
|
||||
permissions = channel.permissions_for(guild.me)
|
||||
if not permissions.send_messages:
|
||||
await message.author.send(f'I don\'t have permission to send text messages in channel {channel} '
|
||||
f'on server {guild}')
|
||||
return
|
||||
|
||||
status_msg += f' ✅ Sending messages\n'
|
||||
|
||||
await channel.send(status_msg)
|
||||
|
||||
def setup(bot):
|
||||
global logger
|
||||
|
||||
@ -11,23 +11,24 @@ import pytz
|
||||
from discord.ext import commands
|
||||
|
||||
from utils.misc import CustomFormatter
|
||||
from .poll import Poll
|
||||
from models.poll import Poll
|
||||
from utils.paginator import embed_list_paginated
|
||||
from essentials.multi_server import get_server_pre, ask_for_server, ask_for_channel
|
||||
from essentials.settings import SETTINGS
|
||||
from utils.poll_name_generator import generate_word
|
||||
from essentials.exceptions import StopWizard
|
||||
|
||||
## A-Z Emojis for Discord
|
||||
# A-Z Emojis for Discord
|
||||
AZ_EMOJIS = [(b'\\U0001f1a'.replace(b'a', bytes(hex(224 + (6 + i))[2:], "utf-8"))).decode("unicode-escape") for i in
|
||||
range(26)]
|
||||
|
||||
|
||||
class PollControls(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
#self.bot.loop.create_task(self.close_polls())
|
||||
self.bot.loop.create_task(self.close_polls())
|
||||
self.ignore_next_removed_reaction = {}
|
||||
#
|
||||
|
||||
# # General Methods
|
||||
|
||||
def get_label(self, message: discord.Message):
|
||||
@ -45,6 +46,10 @@ class PollControls(commands.Cog):
|
||||
"""This function runs every 60 seconds to schedule prepared polls and close expired polls"""
|
||||
while True:
|
||||
try:
|
||||
if not hasattr(self.bot, 'db'):
|
||||
await asyncio.sleep(30)
|
||||
continue
|
||||
|
||||
query = self.bot.db.polls.find({'active': False, 'activation': {"$not": re.compile("0")}})
|
||||
if query:
|
||||
for pd in [poll async for poll in query]:
|
||||
@ -83,7 +88,7 @@ class PollControls(commands.Cog):
|
||||
logger.exception(ex)
|
||||
pass
|
||||
|
||||
await asyncio.sleep(30)
|
||||
await asyncio.sleep(60)
|
||||
|
||||
def get_lock(self, server_id):
|
||||
if not self.bot.locks.get(server_id):
|
||||
@ -119,7 +124,7 @@ class PollControls(commands.Cog):
|
||||
embed.set_footer(text=footer_text)
|
||||
await ctx.send(embed=embed)
|
||||
|
||||
# # Commands
|
||||
# Commands
|
||||
@commands.command()
|
||||
async def activate(self, ctx, *, short=None):
|
||||
"""Activate a prepared poll. Parameter: <label>"""
|
||||
@ -229,6 +234,31 @@ class PollControls(commands.Cog):
|
||||
await self.say_error(ctx, error)
|
||||
await ctx.invoke(self.show)
|
||||
|
||||
@commands.command()
|
||||
async def copy(self, ctx, *, short=None):
|
||||
'''Copy a poll. Parameter: <label>'''
|
||||
server = await ask_for_server(self.bot, ctx.message, short)
|
||||
if not server:
|
||||
return
|
||||
|
||||
if short is None:
|
||||
pre = await get_server_pre(self.bot, ctx.message.guild)
|
||||
error = f'Please specify the label of a poll after the copy command. \n' \
|
||||
f'`{pre}copy <poll_label>`'
|
||||
await self.say_error(ctx, error)
|
||||
|
||||
else:
|
||||
p = await Poll.load_from_db(self.bot, server.id, short)
|
||||
if p is not None:
|
||||
text = await get_server_pre(self.bot, server) + p.to_command()
|
||||
await self.say_embed(ctx, text, title="Paste this to create a copy of the poll")
|
||||
else:
|
||||
error = f'Poll with label "{short}" was not found. Listing all open polls.'
|
||||
# pre = await get_server_pre(self.bot, ctx.message.server)
|
||||
# footer = f'Type {pre}show to display all polls'
|
||||
await self.say_error(ctx, error)
|
||||
await ctx.invoke(self.show)
|
||||
|
||||
@commands.command()
|
||||
async def export(self, ctx, *, short=None):
|
||||
'''Export a poll. Parameter: <label>'''
|
||||
@ -317,87 +347,96 @@ class PollControls(commands.Cog):
|
||||
pre = await get_server_pre(self.bot, server)
|
||||
footer = f'Type {pre}show to display all polls'
|
||||
await self.say_error(ctx, error, footer)
|
||||
#
|
||||
# @commands.command()
|
||||
# async def cmd(self, ctx, *, cmd=None):
|
||||
# '''The old, command style way paired with the wizard.'''
|
||||
|
||||
@commands.command()
|
||||
async def cmd(self, ctx, *, cmd=None):
|
||||
'''The old, command style way paired with the wizard.'''
|
||||
# await self.say_embed(ctx, say_text='This command is temporarily disabled.')
|
||||
# # server = await ask_for_server(self.bot, ctx.message)
|
||||
# # if not server:
|
||||
# # return
|
||||
# # pre = await get_server_pre(self.bot, server)
|
||||
# # try:
|
||||
# # # generate the argparser and handle invalid stuff
|
||||
# # descr = 'Accept poll settings via commandstring. \n\n' \
|
||||
# # '**Wrap all arguments in quotes like this:** \n' \
|
||||
# # f'{pre}cmd -question \"What tea do you like?\" -o \"green, black, chai\"\n\n' \
|
||||
# # 'The Order of arguments doesn\'t matter. If an argument is missing, it will use the default value. ' \
|
||||
# # 'If an argument is invalid, the wizard will step in. ' \
|
||||
# # 'If the command string is invalid, you will get this error :)'
|
||||
# # parser = argparse.ArgumentParser(description=descr, formatter_class=CustomFormatter, add_help=False)
|
||||
# # parser.add_argument('-question', '-q')
|
||||
# # parser.add_argument('-label', '-l', default=str(await generate_word(self.bot, server.id)))
|
||||
# # parser.add_argument('-options', '-o')
|
||||
# # parser.add_argument('-multiple_choice', '-mc', default='1')
|
||||
# # parser.add_argument('-roles', '-r', default='all')
|
||||
# # parser.add_argument('-weights', '-w', default='none')
|
||||
# # parser.add_argument('-deadline', '-d', default='0')
|
||||
# # parser.add_argument('-anonymous', '-a', action="store_true")
|
||||
# #
|
||||
# # helpstring = parser.format_help()
|
||||
# # helpstring = helpstring.replace("pollmaster.py", f"{pre}cmd ")
|
||||
# #
|
||||
# # if cmd and cmd == 'help':
|
||||
# # await self.say_embed(ctx, say_text=helpstring)
|
||||
# # return
|
||||
# #
|
||||
# # try:
|
||||
# # cmds = shlex.split(cmd)
|
||||
# # except ValueError:
|
||||
# # await self.say_error(ctx, error_text=helpstring)
|
||||
# # return
|
||||
# # except:
|
||||
# # return
|
||||
# #
|
||||
# # try:
|
||||
# # args, unknown_args = parser.parse_known_args(cmds)
|
||||
# # except SystemExit:
|
||||
# # await self.say_error(ctx, error_text=helpstring)
|
||||
# # return
|
||||
# # except:
|
||||
# # return
|
||||
# #
|
||||
# # if unknown_args:
|
||||
# # error_text = f'**There was an error reading the command line options!**.\n' \
|
||||
# # f'Most likely this is because you didn\'t surround the arguments with double quotes like this: ' \
|
||||
# # f'`{pre}cmd -q "question of the poll" -o "yes, no, maybe"`' \
|
||||
# # f'\n\nHere are the arguments I could not understand:\n'
|
||||
# # error_text += '`'+'\n'.join(unknown_args)+'`'
|
||||
# # error_text += f'\n\nHere are the arguments which are ok:\n'
|
||||
# # error_text += '`' + '\n'.join([f'{k}: {v}' for k, v in vars(args).items()]) + '`'
|
||||
# #
|
||||
# # await self.say_error(ctx, error_text=error_text, footer_text=f'type `{pre}cmd help` for details.')
|
||||
# # return
|
||||
# #
|
||||
# # # pass arguments to the wizard
|
||||
# # async def route(poll):
|
||||
# # await poll.set_name(force=args.question)
|
||||
# # await poll.set_short(force=args.label)
|
||||
# # await poll.set_anonymous(force=f'{"yes" if args.anonymous else "no"}')
|
||||
# # await poll.set_options_reaction(force=args.options)
|
||||
# # await poll.set_multiple_choice(force=args.multiple_choice)
|
||||
# # await poll.set_roles(force=args.roles)
|
||||
# # await poll.set_weights(force=args.weights)
|
||||
# # await poll.set_duration(force=args.deadline)
|
||||
# #
|
||||
# # poll = await self.wizard(ctx, route, server)
|
||||
# # if poll:
|
||||
# # await poll.post_embed(destination=poll.channel)
|
||||
# # except Exception as error:
|
||||
# # logger.error("ERROR IN pm!cmd")
|
||||
# # logger.exception(error)
|
||||
#
|
||||
#
|
||||
|
||||
server = await ask_for_server(self.bot, ctx.message)
|
||||
if not server:
|
||||
return
|
||||
pre = await get_server_pre(self.bot, server)
|
||||
try:
|
||||
# generate the argparser and handle invalid stuff
|
||||
descr = 'Accept poll settings via commandstring. \n\n' \
|
||||
'**Wrap all arguments in quotes like this:** \n' \
|
||||
f'{pre}cmd -question \"What tea do you like?\" -o \"green, black, chai\"\n\n' \
|
||||
'The Order of arguments doesn\'t matter. If an argument is missing, it will use the default value. ' \
|
||||
'If an argument is invalid, the wizard will step in. ' \
|
||||
'If the command string is invalid, you will get this error :)'
|
||||
parser = argparse.ArgumentParser(description=descr, formatter_class=CustomFormatter, add_help=False)
|
||||
parser.add_argument('-question', '-q')
|
||||
parser.add_argument('-label', '-l', default=str(await generate_word(self.bot, server.id)))
|
||||
parser.add_argument('-anonymous', '-a', action="store_true")
|
||||
parser.add_argument('-options', '-o')
|
||||
parser.add_argument('-survey_flags', '-sf', default='0')
|
||||
parser.add_argument('-multiple_choice', '-mc', default='1')
|
||||
parser.add_argument('-hide_votes', '-h', action="store_true")
|
||||
parser.add_argument('-roles', '-r', default='all')
|
||||
parser.add_argument('-weights', '-w', default='none')
|
||||
parser.add_argument('-prepare', '-p', default='-1')
|
||||
parser.add_argument('-deadline', '-d', default='0')
|
||||
|
||||
helpstring = parser.format_help()
|
||||
helpstring = helpstring.replace("pollmaster.py", f"{pre}cmd ")
|
||||
|
||||
if not cmd or len(cmd) < 2 or cmd == 'help':
|
||||
# Shlex will block if the string is empty
|
||||
await self.say_embed(ctx, say_text=helpstring)
|
||||
return
|
||||
|
||||
try:
|
||||
cmds = shlex.split(cmd)
|
||||
except ValueError:
|
||||
await self.say_error(ctx, error_text=helpstring)
|
||||
return
|
||||
except:
|
||||
return
|
||||
|
||||
try:
|
||||
args, unknown_args = parser.parse_known_args(cmds)
|
||||
except SystemExit:
|
||||
await self.say_error(ctx, error_text=helpstring)
|
||||
return
|
||||
except:
|
||||
return
|
||||
|
||||
if unknown_args:
|
||||
error_text = f'**There was an error reading the command line options!**.\n' \
|
||||
f'Most likely this is because you didn\'t surround the arguments with double quotes like this: ' \
|
||||
f'`{pre}cmd -q "question of the poll" -o "yes, no, maybe"`' \
|
||||
f'\n\nHere are the arguments I could not understand:\n'
|
||||
error_text += '`'+'\n'.join(unknown_args)+'`'
|
||||
error_text += f'\n\nHere are the arguments which are ok:\n'
|
||||
error_text += '`' + '\n'.join([f'{k}: {v}' for k, v in vars(args).items()]) + '`'
|
||||
|
||||
await self.say_error(ctx, error_text=error_text, footer_text=f'type `{pre}cmd help` for details.')
|
||||
return
|
||||
|
||||
# pass arguments to the wizard
|
||||
async def route(poll):
|
||||
await poll.set_name(ctx, force=args.question)
|
||||
await poll.set_short(ctx, force=args.label)
|
||||
await poll.set_anonymous(ctx, force=f'{"yes" if args.anonymous else "no"}')
|
||||
await poll.set_options_reaction(ctx, force=args.options)
|
||||
await poll.set_survey_flags(ctx, force=args.survey_flags)
|
||||
await poll.set_multiple_choice(ctx, force=args.multiple_choice)
|
||||
await poll.set_hide_vote_count(ctx, force=f'{"yes" if args.hide_votes else "no"}')
|
||||
await poll.set_roles(ctx, force=args.roles)
|
||||
await poll.set_weights(ctx, force=args.weights)
|
||||
await poll.set_preparation(ctx, force=args.prepare)
|
||||
await poll.set_duration(ctx, force=args.deadline)
|
||||
|
||||
poll = await self.wizard(ctx, route, server)
|
||||
if poll:
|
||||
await poll.post_embed(poll.channel)
|
||||
|
||||
except Exception as error:
|
||||
logger.error("ERROR IN pm!cmd")
|
||||
logger.exception(error)
|
||||
|
||||
|
||||
@commands.command()
|
||||
async def quick(self, ctx, *, cmd=None):
|
||||
'''Create a quick poll with just a question and some options. Parameters: <Question> (optional)'''
|
||||
@ -411,6 +450,7 @@ class PollControls(commands.Cog):
|
||||
await poll.set_anonymous(ctx, force='no')
|
||||
await poll.set_options_reaction(ctx)
|
||||
await poll.set_multiple_choice(ctx, force='1')
|
||||
await poll.set_hide_vote_count(ctx, force='no')
|
||||
await poll.set_roles(ctx, force='all')
|
||||
await poll.set_weights(ctx, force='none')
|
||||
await poll.set_duration(ctx, force='0')
|
||||
@ -432,7 +472,9 @@ class PollControls(commands.Cog):
|
||||
await poll.set_preparation(ctx)
|
||||
await poll.set_anonymous(ctx)
|
||||
await poll.set_options_reaction(ctx)
|
||||
await poll.set_survey_flags(ctx)
|
||||
await poll.set_multiple_choice(ctx)
|
||||
await poll.set_hide_vote_count(ctx)
|
||||
await poll.set_roles(ctx)
|
||||
await poll.set_weights(ctx)
|
||||
await poll.set_duration(ctx)
|
||||
@ -441,6 +483,29 @@ class PollControls(commands.Cog):
|
||||
if poll:
|
||||
await poll.post_embed(ctx.message.author)
|
||||
|
||||
@commands.command()
|
||||
async def advanced(self, ctx, *, cmd=None):
|
||||
"""Poll with more options. Parameters: <Question> (optional)"""
|
||||
server = await ask_for_server(self.bot, ctx.message)
|
||||
if not server:
|
||||
return
|
||||
|
||||
async def route(poll):
|
||||
await poll.set_name(ctx, force=cmd)
|
||||
await poll.set_short(ctx)
|
||||
await poll.set_anonymous(ctx)
|
||||
await poll.set_options_reaction(ctx)
|
||||
await poll.set_survey_flags(ctx)
|
||||
await poll.set_multiple_choice(ctx)
|
||||
await poll.set_hide_vote_count(ctx)
|
||||
await poll.set_roles(ctx)
|
||||
await poll.set_weights(ctx)
|
||||
await poll.set_duration(ctx)
|
||||
|
||||
poll = await self.wizard(ctx, route, server)
|
||||
if poll:
|
||||
await poll.post_embed(poll.channel)
|
||||
|
||||
@commands.command()
|
||||
async def new(self, ctx, *, cmd=None):
|
||||
"""Start the poll wizard to create a new poll step by step. Parameters: <Question> (optional)"""
|
||||
@ -454,8 +519,9 @@ class PollControls(commands.Cog):
|
||||
await poll.set_anonymous(ctx)
|
||||
await poll.set_options_reaction(ctx)
|
||||
await poll.set_multiple_choice(ctx)
|
||||
await poll.set_roles(ctx)
|
||||
await poll.set_weights(ctx)
|
||||
await poll.set_hide_vote_count(ctx, force='no')
|
||||
await poll.set_roles(ctx, force='all')
|
||||
await poll.set_weights(ctx, force='none')
|
||||
await poll.set_duration(ctx)
|
||||
|
||||
poll = await self.wizard(ctx, route, server)
|
||||
@ -468,13 +534,14 @@ class PollControls(commands.Cog):
|
||||
if not channel:
|
||||
return
|
||||
|
||||
pre = await get_server_pre(self.bot, server)
|
||||
|
||||
# Permission Check
|
||||
member = server.get_member(ctx.message.author.id)
|
||||
if not member.guild_permissions.manage_guild:
|
||||
result = await self.bot.db.config.find_one({'_id': str(server.id)})
|
||||
if result and result.get('admin_role') not in [r.name for r in member.roles] and result.get(
|
||||
'user_role') not in [r.name for r in member.roles]:
|
||||
pre = await get_server_pre(self.bot, server)
|
||||
await ctx.message.author.send('You don\'t have sufficient rights to start new polls on this server. '
|
||||
'A server administrator has to assign the user or admin role to you. '
|
||||
f'To view and set the permissions, an admin can use `{pre}userrole` and '
|
||||
@ -485,35 +552,20 @@ class PollControls(commands.Cog):
|
||||
poll = Poll(self.bot, ctx, server, channel)
|
||||
|
||||
## Route to define object, passed as argument for different constructors
|
||||
if ctx.message and ctx.message.content and not ctx.message.content.startswith(f'{pre}cmd '):
|
||||
poll.wizard_messages.append(ctx.message)
|
||||
try:
|
||||
await route(poll)
|
||||
poll.finalize()
|
||||
await poll.clean_up(ctx.channel)
|
||||
except StopWizard:
|
||||
await poll.clean_up(ctx.channel)
|
||||
return
|
||||
|
||||
# Finalize
|
||||
await poll.save_to_db()
|
||||
return poll
|
||||
|
||||
# # BOT EVENTS (@bot.event)
|
||||
# async def on_socket_raw_receive(self, raw_msg):
|
||||
# print(raw_msg)
|
||||
# if not isinstance(raw_msg, str):
|
||||
# return
|
||||
# msg = json.loads(raw_msg)
|
||||
# type = msg.get("t")
|
||||
# data = msg.get("d")
|
||||
# if not data:
|
||||
# return
|
||||
# # emoji = data.get("emoji")
|
||||
# # user_id = data.get("user_id")
|
||||
# # message_id = data.get("message_id")
|
||||
# if type == "MESSAGE_REACTION_ADD":
|
||||
# await self.do_on_reaction_add(data)
|
||||
# elif type == "MESSAGE_REACTION_REMOVE":
|
||||
# #await self.do_on_reaction_remove(data)
|
||||
# pass
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_raw_reaction_remove(self, data):
|
||||
# get emoji symbol
|
||||
@ -672,6 +724,10 @@ class PollControls(commands.Cog):
|
||||
description='', color=SETTINGS.color)
|
||||
embed.set_author(name=f" >> {p.short}", icon_url=SETTINGS.author_icon)
|
||||
|
||||
# created by
|
||||
created_by = server.get_member(int(p.author.id))
|
||||
embed.add_field(name=f'Created by:', value=f'{created_by if created_by else "<Deleted User>"}', inline=False)
|
||||
|
||||
# vote rights
|
||||
vote_rights = await p.has_required_role(member)
|
||||
embed.add_field(name=f'{"Can you vote?" if is_open else "Could you vote?"}',
|
||||
@ -679,7 +735,7 @@ class PollControls(commands.Cog):
|
||||
|
||||
# edit rights
|
||||
edit_rights = False
|
||||
if str(member.id) == str(p.author):
|
||||
if str(member.id) == str(p.author.id):
|
||||
edit_rights = True
|
||||
elif member.guild_permissions.manage_guild:
|
||||
edit_rights = True
|
||||
@ -724,7 +780,7 @@ class PollControls(commands.Cog):
|
||||
await user.send(embed=embed)
|
||||
|
||||
# send current details of who currently voted for what
|
||||
if not p.anonymous and p.votes.__len__() > 0:
|
||||
if (not p.open or not p.hide_count) and not p.anonymous and p.votes.__len__() > 0:
|
||||
msg = '--------------------------------------------\n' \
|
||||
'CURRENT VOTES\n' \
|
||||
'--------------------------------------------\n'
|
||||
@ -734,17 +790,21 @@ class PollControls(commands.Cog):
|
||||
msg += "**" +o+":**"
|
||||
c = 0
|
||||
for user_id in p.votes:
|
||||
member = server.get_member(user_id)
|
||||
member = server.get_member(int(user_id))
|
||||
if not member or i not in p.votes[str(user_id)]['choices']:
|
||||
continue
|
||||
c += 1
|
||||
name = member.nick
|
||||
if not name:
|
||||
name = member.name
|
||||
if not name:
|
||||
name = "<Deleted User>"
|
||||
msg += f'\n{name}'
|
||||
if p.votes[str(user_id)]['weight'] != 1:
|
||||
msg += f' (weight: {p.votes[str(user_id)]["weight"]})'
|
||||
# msg += ': ' + ', '.join([AZ_EMOJIS[c]+" "+p.options_reaction[c] for c in p.votes[user_id]['choices']])
|
||||
if i in p.survey_flags:
|
||||
msg += f': {p.votes[str(user_id)]["answers"][p.survey_flags.index(i)]}'
|
||||
if msg.__len__() > 1500:
|
||||
await user.send(msg)
|
||||
msg = ''
|
||||
@ -754,6 +814,29 @@ class PollControls(commands.Cog):
|
||||
|
||||
if msg.__len__() > 0:
|
||||
await user.send(msg)
|
||||
elif (not p.open or not p.hide_count) and p.anonymous and p.survey_flags.__len__() > 0 and p.votes.__len__() > 0:
|
||||
msg = '--------------------------------------------\n' \
|
||||
'Custom Answers (Anonymous)\n' \
|
||||
'--------------------------------------------\n'
|
||||
has_answers = False
|
||||
for i, o in enumerate(p.options_reaction):
|
||||
if i not in p.survey_flags:
|
||||
continue
|
||||
custom_answers = ''
|
||||
for user_id in p.votes:
|
||||
if i in p.votes[str(user_id)]["choices"]:
|
||||
has_answers = True
|
||||
custom_answers += f'\n{p.votes[str(user_id)]["answers"][p.survey_flags.index(i)]}'
|
||||
if custom_answers.__len__() > 0:
|
||||
msg += AZ_EMOJIS[i] + " "
|
||||
msg += "**" + o + ":**"
|
||||
msg += custom_answers
|
||||
msg += '\n\n'
|
||||
if msg.__len__() > 1500:
|
||||
await user.send(msg)
|
||||
msg = ''
|
||||
if has_answers and msg.__len__() > 0:
|
||||
await user.send(msg)
|
||||
return
|
||||
|
||||
# Assume: User wants to vote with reaction
|
||||
@ -770,7 +853,6 @@ class PollControls(commands.Cog):
|
||||
self.ignore_next_removed_reaction[str(message.id) + str(emoji)] = user_id
|
||||
asyncio.ensure_future(message.remove_reaction(emoji, user))
|
||||
|
||||
|
||||
# order here is crucial since we can't determine if a reaction was removed by the bot or user
|
||||
# update database with vote
|
||||
await p.vote(member, emoji, message, lock)
|
||||
@ -785,6 +867,7 @@ class PollControls(commands.Cog):
|
||||
# await message.remove_reaction(r.emoji, user)
|
||||
# pass
|
||||
|
||||
|
||||
def setup(bot):
|
||||
global logger
|
||||
logger = logging.getLogger('bot')
|
||||
|
||||
@ -21,7 +21,7 @@ async def get_pre(bot, message):
|
||||
|
||||
|
||||
async def get_server_pre(bot, server):
|
||||
'''Gets the prefix for a server.'''
|
||||
"""Gets the prefix for a server."""
|
||||
try:
|
||||
#result = await bot.db.config.find_one({'_id': str(server.id)})
|
||||
result = bot.pre[str(server.id)]
|
||||
@ -33,7 +33,7 @@ async def get_server_pre(bot, server):
|
||||
|
||||
|
||||
async def get_servers(bot, message, short=None):
|
||||
'''Get best guess of relevant shared servers'''
|
||||
"""Get best guess of relevant shared servers"""
|
||||
if message.guild is None:
|
||||
list_of_shared_servers = []
|
||||
for s in bot.guilds:
|
||||
|
||||
0
models/__init__.py
Normal file
0
models/__init__.py
Normal file
@ -3,7 +3,8 @@ import codecs
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import random
|
||||
|
||||
import dateparser
|
||||
import pytz
|
||||
import regex
|
||||
@ -23,13 +24,13 @@ from utils.misc import possible_timezones
|
||||
|
||||
logger = logging.getLogger('bot')
|
||||
|
||||
## Helvetica is the closest font to Whitney (discord uses Whitney) in afm
|
||||
## This is used to estimate text width and adjust the layout of the embeds
|
||||
# Helvetica is the closest font to Whitney (discord uses Whitney) in afm
|
||||
# This is used to estimate text width and adjust the layout of the embeds
|
||||
afm_fname = os.path.join(rcParams['datapath'], 'fonts', 'afm', 'phvr8a.afm')
|
||||
with open(afm_fname, 'rb') as fh:
|
||||
afm = AFM(fh)
|
||||
|
||||
## A-Z Emojis for Discord
|
||||
# A-Z Emojis for Discord
|
||||
AZ_EMOJIS = [(b'\\U0001f1a'.replace(b'a', bytes(hex(224 + (6 + i))[2:], "utf-8"))).decode("unicode-escape") for i in
|
||||
range(26)]
|
||||
|
||||
@ -57,10 +58,12 @@ class Poll:
|
||||
self.name = "Quick Poll"
|
||||
self.short = str(uuid4())[0:23]
|
||||
self.anonymous = False
|
||||
self.hide_count = False
|
||||
self.reaction = True
|
||||
self.multiple_choice = 1
|
||||
self.options_reaction = ['yes', 'no']
|
||||
self.options_reaction_default = False
|
||||
self.survey_flags = []
|
||||
# self.options_traditional = []
|
||||
# self.options_traditional_default = False
|
||||
self.roles = ['@everyone']
|
||||
@ -76,6 +79,18 @@ class Poll:
|
||||
self.activation_tz = 0.0
|
||||
self.votes = {}
|
||||
|
||||
self.wizard_messages = []
|
||||
|
||||
def get_preset_options(self, number):
|
||||
if number == 1:
|
||||
return ['✅', '❎']
|
||||
elif number == 2:
|
||||
return ['👍', '🤐', '👎']
|
||||
elif number == 3:
|
||||
return ['😍', '👍', '🤐', '👎', '🤢']
|
||||
elif number == 4:
|
||||
return ['in favour', 'against', 'abstaining']
|
||||
|
||||
async def is_open(self, update_db=True):
|
||||
if self.server is None:
|
||||
self.open = True
|
||||
@ -102,7 +117,9 @@ class Poll:
|
||||
embed = discord.Embed(title="Poll creation Wizard", description=text, color=SETTINGS.color)
|
||||
if footer:
|
||||
embed.set_footer(text="Type `stop` to cancel the wizard.")
|
||||
return await ctx.send(embed=embed)
|
||||
msg = await ctx.send(embed=embed)
|
||||
self.wizard_messages.append(msg)
|
||||
return msg
|
||||
|
||||
async def wizard_says_edit(self, message, text, add=False):
|
||||
if add and message.embeds.__len__() > 0:
|
||||
@ -127,9 +144,13 @@ class Poll:
|
||||
"""Pre-parse user input for wizard"""
|
||||
def check(m):
|
||||
return m.author == self.author
|
||||
try:
|
||||
reply = await self.bot.wait_for('message', timeout=180, check=check)
|
||||
except asyncio.TimeoutError:
|
||||
raise StopWizard
|
||||
|
||||
reply = await self.bot.wait_for('message', check=check)
|
||||
if reply and reply.content:
|
||||
self.wizard_messages.append(reply)
|
||||
if reply.content.startswith(await get_pre(self.bot, reply)):
|
||||
await self.wizard_says(ctx, f'You can\'t use bot commands during the Poll Creation Wizard.\n'
|
||||
f'Stopping the Wizard and then executing the command:\n`{reply.content}`',
|
||||
@ -144,7 +165,8 @@ class Poll:
|
||||
else:
|
||||
raise InvalidInput
|
||||
|
||||
def sanitize_string(self, string):
|
||||
@staticmethod
|
||||
def sanitize_string(string):
|
||||
"""Sanitize user input for wizard"""
|
||||
# sanitize input
|
||||
if string is None:
|
||||
@ -239,7 +261,6 @@ class Poll:
|
||||
await self.add_error(message,
|
||||
f'**The label `{reply}` is not unique on this server. Choose a different one!**')
|
||||
|
||||
|
||||
async def set_preparation(self, ctx, force=None):
|
||||
"""Set the preparation conditions for the Poll."""
|
||||
async def get_valid(in_reply):
|
||||
@ -269,6 +290,9 @@ class Poll:
|
||||
raise DateOutOfRange(dt)
|
||||
return dt
|
||||
|
||||
if str(force) == '-1':
|
||||
return
|
||||
|
||||
try:
|
||||
dt = await get_valid(force)
|
||||
self.activation = dt
|
||||
@ -302,7 +326,7 @@ class Poll:
|
||||
self.active = False
|
||||
break
|
||||
except InvalidInput:
|
||||
await self.add_error(message, '**I could not understand that format.**')
|
||||
await self.add_error(message, '**Specify the activation time in a format i can understand.**')
|
||||
except TypeError:
|
||||
await self.add_error(message, '**Type Error.**')
|
||||
except DateOutOfRange as e:
|
||||
@ -404,7 +428,6 @@ class Poll:
|
||||
except OutOfRange:
|
||||
await self.add_error(message, '**You can\'t have more choices than options.**')
|
||||
|
||||
|
||||
async def set_options_reaction(self, ctx, force=None):
|
||||
"""Set the answers / options of the Poll."""
|
||||
async def get_valid(in_reply):
|
||||
@ -418,7 +441,7 @@ class Poll:
|
||||
return int(split[0])
|
||||
else:
|
||||
raise WrongNumberOfArguments
|
||||
elif 1 < split.__len__() <= 26:
|
||||
elif 1 < split.__len__() <= 18:
|
||||
split = [self.sanitize_string(o) for o in split]
|
||||
if any([len(o) < 1 for o in split]):
|
||||
raise InvalidInput
|
||||
@ -427,22 +450,11 @@ class Poll:
|
||||
else:
|
||||
raise WrongNumberOfArguments
|
||||
|
||||
def get_preset_options(number):
|
||||
if number == 1:
|
||||
return ['✅', '❎']
|
||||
elif number == 2:
|
||||
return ['👍', '🤐', '👎']
|
||||
elif number == 3:
|
||||
return ['😍', '👍', '🤐', '👎', '🤢']
|
||||
elif number == 4:
|
||||
return ['in favour', 'against', 'abstaining']
|
||||
|
||||
|
||||
try:
|
||||
options = await get_valid(force)
|
||||
self.options_reaction_default = False
|
||||
if isinstance(options, int):
|
||||
self.options_reaction = get_preset_options(options)
|
||||
self.options_reaction = self.get_preset_options(options)
|
||||
if options <= 3:
|
||||
self.options_reaction_default = True
|
||||
else:
|
||||
@ -473,7 +485,7 @@ class Poll:
|
||||
options = await get_valid(reply)
|
||||
self.options_reaction_default = False
|
||||
if isinstance(options, int):
|
||||
self.options_reaction = get_preset_options(options)
|
||||
self.options_reaction = self.get_preset_options(options)
|
||||
if options <= 3:
|
||||
self.options_reaction_default = True
|
||||
else:
|
||||
@ -483,11 +495,115 @@ class Poll:
|
||||
except InvalidInput:
|
||||
await self.add_error(message,
|
||||
'**Invalid entry. Type `1`, `2`, `3` or `4` or a comma separated list of '
|
||||
'up to 26 options.**')
|
||||
'up to 18 options.**')
|
||||
except WrongNumberOfArguments:
|
||||
await self.add_error(message,
|
||||
'**You need more than 1 option! Type them in a comma separated list.**')
|
||||
'**You need more than 1 and less than 19 options! '
|
||||
'Type them in a comma separated list.**')
|
||||
|
||||
async def set_survey_flags(self, ctx, force=None):
|
||||
"""Decide which Options will ask for user input."""
|
||||
async def get_valid(in_reply):
|
||||
if not in_reply:
|
||||
raise InvalidInput
|
||||
split = [r.strip() for r in in_reply.split(",")]
|
||||
|
||||
if not split or split.__len__() == 1 and split[0] == '0':
|
||||
return []
|
||||
|
||||
if not all([r.isdigit() for r in split]):
|
||||
raise ExpectedInteger
|
||||
|
||||
if any([1 > int(r) or int(r) > len(self.options_reaction) for r in split]):
|
||||
raise OutOfRange
|
||||
|
||||
return [int(r)-1 for r in split]
|
||||
|
||||
if self.options_reaction_default:
|
||||
return
|
||||
|
||||
try:
|
||||
self.survey_flags = await get_valid(force)
|
||||
return
|
||||
except InputError:
|
||||
pass
|
||||
|
||||
text = ("**Which options should ask the user for a custom answer?**\n"
|
||||
"Type `0` to skip survey options.\n"
|
||||
"If you want multiple survey options, separate the numbers with a comma.\n"
|
||||
"\n"
|
||||
"`0 - None (classic poll)`\n"
|
||||
)
|
||||
for i, option in enumerate(self.options_reaction):
|
||||
text += f'`{i + 1} - {option}`\n'
|
||||
text += ("\n"
|
||||
"If the user votes for one of these options, the bot will PM them and ask them to provide a text "
|
||||
"input. You can use this to do surveys or to gather feedback for example.\n")
|
||||
message = await self.wizard_says(ctx, text)
|
||||
|
||||
while True:
|
||||
try:
|
||||
if force:
|
||||
reply = force
|
||||
force = None
|
||||
else:
|
||||
reply = await self.get_user_reply(ctx)
|
||||
self.survey_flags = await get_valid(reply)
|
||||
await self.add_vaild(
|
||||
message, f'{"None" if self.survey_flags.__len__() == 0 else ", ".join(str(f + 1) for f in self.survey_flags)}'
|
||||
)
|
||||
break
|
||||
except InvalidInput:
|
||||
await self.add_error(message, '**I can\'t read this input.**')
|
||||
except ExpectedInteger:
|
||||
await self.add_error(message, '**Only type positive numbers separated by a comma.**')
|
||||
except OutOfRange:
|
||||
await self.add_error(message, '**Only type numbers you can see in the list.**')
|
||||
|
||||
async def set_hide_vote_count(self, ctx, force=None):
|
||||
"""Determine the live vote count is hidden or shown."""
|
||||
async def get_valid(in_reply):
|
||||
if not in_reply:
|
||||
raise InvalidInput
|
||||
is_true = ['yes', '1']
|
||||
is_false = ['no', '0']
|
||||
in_reply = self.sanitize_string(in_reply)
|
||||
if not in_reply:
|
||||
raise InvalidInput
|
||||
elif in_reply.lower() in is_true:
|
||||
return True
|
||||
elif in_reply.lower() in is_false:
|
||||
return False
|
||||
else:
|
||||
raise InvalidInput
|
||||
|
||||
try:
|
||||
self.hide_count = await get_valid(force)
|
||||
return
|
||||
except InputError:
|
||||
pass
|
||||
|
||||
text = ("**Do you want to hide the live vote count?**\n"
|
||||
"\n"
|
||||
"`0 - No, show it (Default)`\n"
|
||||
"`1 - Yes, hide it`\n"
|
||||
"\n"
|
||||
"You will still be able to see the vote count once the poll is closed. This settings will just hide "
|
||||
"the vote count while the poll is active.")
|
||||
message = await self.wizard_says(ctx, text)
|
||||
|
||||
while True:
|
||||
try:
|
||||
if force:
|
||||
reply = force
|
||||
force = None
|
||||
else:
|
||||
reply = await self.get_user_reply(ctx)
|
||||
self.hide_count = await get_valid(reply)
|
||||
await self.add_vaild(message, f'{"Yes" if self.hide_count else "No"}')
|
||||
break
|
||||
except InvalidInput:
|
||||
await self.add_error(message, '**You can only answer with `yes` | `1` or `no` | `0`!**')
|
||||
|
||||
async def set_roles(self, ctx, force=None):
|
||||
"""Set role restrictions for the Poll."""
|
||||
@ -500,7 +616,7 @@ class Poll:
|
||||
if split.__len__() == 1 and split[0] in ['0', 'all', 'everyone']:
|
||||
return ['@everyone']
|
||||
|
||||
if n_roles <= 20 and force is None:
|
||||
if n_roles <= 20 and not force:
|
||||
if not all([r.isdigit() for r in split]):
|
||||
raise ExpectedInteger
|
||||
elif any([int(r) > n_roles for r in split]):
|
||||
@ -614,6 +730,7 @@ class Poll:
|
||||
force = None
|
||||
else:
|
||||
reply = await self.get_user_reply(ctx)
|
||||
print(reply)
|
||||
w_n = await get_valid(reply, self.server.roles)
|
||||
self.weights_roles = w_n[0]
|
||||
self.weights_numbers = w_n[1]
|
||||
@ -690,7 +807,7 @@ class Poll:
|
||||
await self.add_vaild(message, self.duration.strftime('%d-%b-%Y %H:%M %Z'))
|
||||
break
|
||||
except InvalidInput:
|
||||
await self.add_error(message, '**I could not understand that format.**')
|
||||
await self.add_error(message, '**Specify the deadline in a format I can understand.**')
|
||||
except TypeError:
|
||||
await self.add_error(message, '**Type Error.**')
|
||||
except DateOutOfRange as e:
|
||||
@ -699,6 +816,83 @@ class Poll:
|
||||
def finalize(self):
|
||||
self.time_created = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
|
||||
|
||||
async def clean_up(self, channel):
|
||||
if isinstance(channel, discord.TextChannel):
|
||||
await channel.delete_messages(self.wizard_messages)
|
||||
|
||||
async def ask_for_input_DM(self, user, title, text):
|
||||
embed = discord.Embed(title=title, description=text, color=SETTINGS.color)
|
||||
embed.set_footer(text='You can answer anywhere.')
|
||||
message = await user.send(embed=embed)
|
||||
|
||||
def check(m):
|
||||
return m.author == user
|
||||
|
||||
try:
|
||||
reply = await self.bot.wait_for('message', timeout=15, check=check)
|
||||
if reply and reply.content:
|
||||
reply = reply.content
|
||||
else:
|
||||
return None
|
||||
except asyncio.TimeoutError:
|
||||
if message.embeds.__len__() > 0:
|
||||
embed.description = embed.description + '\n\n:exclamation: Request timed out. Vote was counted, ' \
|
||||
'but no custom answer recorded.'
|
||||
await message.edit(embed=embed)
|
||||
return None
|
||||
|
||||
try:
|
||||
reply = self.sanitize_string(reply)
|
||||
except InvalidInput:
|
||||
embed = discord.Embed(title=title,
|
||||
description="Invalid Input. To try again, un-vote and re-vote the option.",
|
||||
color=SETTINGS.color
|
||||
)
|
||||
await user.send(embed=embed)
|
||||
|
||||
if message.embeds.__len__() > 0:
|
||||
embed.description = embed.description + '\n\n✅ ' + reply
|
||||
await message.edit(embed=embed)
|
||||
|
||||
return reply
|
||||
|
||||
def to_command(self):
|
||||
# make new label by increasing a counter at the end
|
||||
try:
|
||||
new_nr = int(self.short[-1]) + 1
|
||||
new_label = self.short[:-1] + str(new_nr)
|
||||
except ValueError:
|
||||
new_label = self.short + "2"
|
||||
|
||||
cmd = "cmd"
|
||||
|
||||
cmd += " -q \"" + self.name + "\""
|
||||
cmd += " -l \"" + new_label + "\""
|
||||
if self.anonymous:
|
||||
cmd += " -a"
|
||||
|
||||
if self.options_reaction_default:
|
||||
for i in range(1, 5):
|
||||
if self.get_preset_options(i) == self.options_reaction:
|
||||
cmd += " -o \"" + str(i) + "\""
|
||||
else:
|
||||
cmd += " -o \"" + ", ".join(self.options_reaction) + "\""
|
||||
|
||||
cmd += " -sf \"" + ", ".join([str(x+1) for x in self.survey_flags]) + "\""
|
||||
cmd += " -mc \"" + str(self.multiple_choice) + "\""
|
||||
if self.hide_count:
|
||||
cmd += " -h"
|
||||
if self.roles != ["@everyone"]:
|
||||
cmd += " -r \"" + ", ".join(self.roles) + "\""
|
||||
if not self.active:
|
||||
cmd += " -p \"specify activation time\""
|
||||
if self.duration == 0:
|
||||
cmd += " -d \"0\""
|
||||
else:
|
||||
cmd += " -d \"specify deadline\""
|
||||
|
||||
return cmd
|
||||
|
||||
async def to_dict(self):
|
||||
if self.channel is None:
|
||||
cid = 0
|
||||
@ -715,11 +909,13 @@ class Poll:
|
||||
'name': self.name,
|
||||
'short': self.short,
|
||||
'anonymous': self.anonymous,
|
||||
'hide_count': self.hide_count,
|
||||
'reaction': self.reaction,
|
||||
'multiple_choice': self.multiple_choice,
|
||||
'options_reaction': self.options_reaction,
|
||||
'reaction_default': self.options_reaction_default,
|
||||
#'options_traditional': self.options_traditional,
|
||||
'survey_flags': self.survey_flags,
|
||||
'roles': self.roles,
|
||||
'weights_roles': self.weights_roles,
|
||||
'weights_numbers': self.weights_numbers,
|
||||
@ -766,7 +962,7 @@ class Poll:
|
||||
f'Question / Name: {self.name}\n'
|
||||
f'Label: {self.short}\n'
|
||||
f'Anonymous: {"Yes" if self.anonymous else "No"}\n'
|
||||
f'Multiple choice: {"Yes" if self.multiple_choice else "No"}\n'
|
||||
f'# Choices: {"Multiple" if self.multiple_choice == 0 else self.multiple_choice}\n'
|
||||
f'Answer options: {", ".join(self.options_reaction)}\n'
|
||||
f'Allowed roles: {", ".join(self.roles) if self.roles.__len__() > 0 else "@everyone"}\n'
|
||||
f'Weights for roles: {weight_str}\n'
|
||||
@ -795,10 +991,21 @@ class Poll:
|
||||
|
||||
if not name:
|
||||
name = member.name
|
||||
export += f'\n{name}'
|
||||
export += f'\n{name}: '
|
||||
if self.votes[str(user_id)]['weight'] != 1:
|
||||
export += f' (weight: {self.votes[str(user_id)]["weight"]})'
|
||||
export += ': ' + ', '.join([self.options_reaction[c] for c in self.votes[str(user_id)]['choices']])
|
||||
# export += ': ' + ', '.join([self.options_reaction[c] for c in self.votes[str(user_id)]['choices']])
|
||||
choice_text_list = []
|
||||
for choice in self.votes[str(user_id)]['choices']:
|
||||
choice_text = self.options_reaction[choice]
|
||||
if choice in self.survey_flags:
|
||||
choice_text += " ("\
|
||||
+ self.votes[str(user_id)]["answers"][self.survey_flags.index(choice)] \
|
||||
+ ") "
|
||||
choice_text_list.append(choice_text)
|
||||
if choice_text_list:
|
||||
export += ', '.join(choice_text_list)
|
||||
|
||||
export += '\n'
|
||||
else:
|
||||
export += '--------------------------------------------\n' \
|
||||
@ -821,6 +1028,28 @@ class Poll:
|
||||
# export += ': ' + ', '.join([self.options_reaction[c] for c in self.votes[str(user_id)]['choices']])
|
||||
export += '\n'
|
||||
|
||||
if self.survey_flags.__len__() > 0:
|
||||
export += '--------------------------------------------\n' \
|
||||
'CUSTOM ANSWERS (RANDOM ORDER)\n' \
|
||||
'--------------------------------------------'
|
||||
for i, o in enumerate(self.options_reaction):
|
||||
if i not in self.survey_flags:
|
||||
continue
|
||||
custom_answers = []
|
||||
for user_id in self.votes:
|
||||
if i in self.votes[str(user_id)]["choices"]:
|
||||
custom_answers.append(f'\n{self.votes[str(user_id)]["answers"][self.survey_flags.index(i)]}')
|
||||
|
||||
export += "\n" + o + ":"
|
||||
if custom_answers.__len__() > 0:
|
||||
random.shuffle(custom_answers) # randomize answers per question
|
||||
for answer in custom_answers:
|
||||
export += answer
|
||||
export += '\n'
|
||||
else:
|
||||
export += "No custom answers were submitted."
|
||||
export += '\n'
|
||||
|
||||
export += ('--------------------------------------------\n'
|
||||
'BOT DETAILS\n'
|
||||
'--------------------------------------------\n'
|
||||
@ -854,6 +1083,13 @@ class Poll:
|
||||
self.name = d['name']
|
||||
self.short = d['short']
|
||||
self.anonymous = d['anonymous']
|
||||
|
||||
# backwards compatibility
|
||||
if 'hide_count' in d.keys():
|
||||
self.hide_count = d['hide_count']
|
||||
else:
|
||||
self.hide_count = False
|
||||
|
||||
self.reaction = d['reaction']
|
||||
|
||||
# backwards compatibility for multiple choice
|
||||
@ -872,6 +1108,13 @@ class Poll:
|
||||
self.options_reaction = d['options_reaction']
|
||||
self.options_reaction_default = d['reaction_default']
|
||||
# self.options_traditional = d['options_traditional']
|
||||
|
||||
# backwards compatibility
|
||||
if 'survey_flags' in d.keys():
|
||||
self.survey_flags = d['survey_flags']
|
||||
else:
|
||||
self.survey_flags = []
|
||||
|
||||
self.roles = d['roles']
|
||||
self.weights_roles = d['weights_roles']
|
||||
self.weights_numbers = d['weights_numbers']
|
||||
@ -945,6 +1188,7 @@ class Poll:
|
||||
|
||||
embed = await self.add_field_custom(name='**Poll Question**', value=self.name, embed=embed)
|
||||
|
||||
if self.roles != ['@everyone']:
|
||||
embed = await self.add_field_custom(name='**Roles**', value=', '.join(self.roles), embed=embed)
|
||||
if len(self.weights_roles) > 0:
|
||||
weights = []
|
||||
@ -954,9 +1198,10 @@ class Poll:
|
||||
|
||||
embed = await self.add_field_custom(name='**Anonymous**', value=self.anonymous, embed=embed)
|
||||
|
||||
# embed = await self.add_field_custom(name='**Multiple Choice**', value=self.multiple_choice, embed=embed)
|
||||
if self.duration != 0:
|
||||
embed = await self.add_field_custom(name='**Deadline**', value=await self.get_poll_status(), embed=embed)
|
||||
embed = await self.add_field_custom(name='**Author**', value=self.author.name, embed=embed)
|
||||
|
||||
# embed = await self.add_field_custom(name='**Author**', value=self.author.name, embed=embed)
|
||||
|
||||
if self.reaction:
|
||||
if self.options_reaction_default:
|
||||
@ -976,34 +1221,47 @@ class Poll:
|
||||
vote_display.append(f'{r} {self.count_votes(i)}')
|
||||
embed = await self.add_field_custom(name=text, value=' '.join(vote_display), embed=embed)
|
||||
else:
|
||||
embed.add_field(name='\u200b', value='\u200b', inline=False)
|
||||
# embed.add_field(name='\u200b', value='\u200b', inline=False)
|
||||
if await self.is_open():
|
||||
text = f'*Vote by adding reactions to the poll*. '
|
||||
head = ""
|
||||
if self.multiple_choice == 0:
|
||||
text += '*You can vote for multiple options.*'
|
||||
head += 'You can vote for multiple options:'
|
||||
elif self.multiple_choice == 1:
|
||||
text += '*You have 1 vote, but can change it.*'
|
||||
head += 'You have 1 vote:'
|
||||
else:
|
||||
text += f'*You have {self.multiple_choice} choices and can change them.*'
|
||||
head += f'You can vote for {self.multiple_choice} options:'
|
||||
else:
|
||||
text = f'*Final Results of the Poll* '
|
||||
head = f'Final Results of the Poll '
|
||||
if self.multiple_choice == 0:
|
||||
text += '*(Multiple Choice).*'
|
||||
head += '(Multiple Choice):'
|
||||
elif self.multiple_choice == 1:
|
||||
text += '*(Single Choice).*'
|
||||
head += '(Single Choice):'
|
||||
else:
|
||||
text += f'*(With up to {self.multiple_choice} choices).*'
|
||||
embed = await self.add_field_custom(name='**Options**', value=text, embed=embed)
|
||||
head += f'(With up to {self.multiple_choice} choices):'
|
||||
# embed = await self.add_field_custom(name='**Options**', value=text, embed=embed)
|
||||
options_text = '**' + head + '**\n'
|
||||
for i, r in enumerate(self.options_reaction):
|
||||
embed = await self.add_field_custom(
|
||||
name=f':regional_indicator_{ascii_lowercase[i]}: {self.count_votes(i)}',
|
||||
value=r,
|
||||
embed=embed
|
||||
)
|
||||
custom_icon = ''
|
||||
if i in self.survey_flags:
|
||||
custom_icon = '🖊'
|
||||
options_text += f':regional_indicator_{ascii_lowercase[i]}:{custom_icon} {r}'
|
||||
if self.hide_count and self.open:
|
||||
options_text += '\n'
|
||||
else:
|
||||
options_text += f' **- {self.count_votes(i)} Votes**\n'
|
||||
# embed = await self.add_field_custom(
|
||||
# name=f':regional_indicator_{ascii_lowercase[i]}:{custom_icon} {self.count_votes(i)}',
|
||||
# value=r,
|
||||
# embed=embed
|
||||
# )
|
||||
embed.add_field(name='\u200b', value=options_text, inline=False)
|
||||
|
||||
# else:
|
||||
# embed = await self.add_field_custom(name='**Options**', value=', '.join(self.get_options()), embed=embed)
|
||||
|
||||
embed.set_footer(text='React with ❔ to get info. It is not a vote option.')
|
||||
custom_text = ""
|
||||
if len(self.survey_flags) > 0:
|
||||
custom_text = " 🖊 next to an option means you can submit a custom answer."
|
||||
embed.set_footer(text='React with ❔ to get info. It is not a vote option.' + custom_text)
|
||||
return embed
|
||||
|
||||
async def post_embed(self, destination):
|
||||
@ -1129,7 +1387,7 @@ class Poll:
|
||||
weight = max(valid_weights)
|
||||
|
||||
if str(user.id) not in self.votes:
|
||||
self.votes[str(user.id)] = {'weight': weight, 'choices': []}
|
||||
self.votes[str(user.id)] = {'weight': weight, 'choices': [], 'answers': []}
|
||||
else:
|
||||
self.votes[str(user.id)]['weight'] = weight
|
||||
|
||||
@ -1157,6 +1415,20 @@ class Poll:
|
||||
await user.send(embed=embed)
|
||||
# refresh_poll = False
|
||||
else:
|
||||
if choice in self.survey_flags:
|
||||
if len(self.votes[str(user.id)]['answers']) != len(self.survey_flags):
|
||||
self.votes[str(user.id)]['answers'] = ['' for i in range(len(self.survey_flags))]
|
||||
custom_input = await self.ask_for_input_DM(
|
||||
user,
|
||||
"Custom Answer",
|
||||
"For this vote option you can provide a custom reply. "
|
||||
"Note that everyone will be able to see the answer. If you don't want to provide a "
|
||||
"custom answer, type \"-\""
|
||||
)
|
||||
if not custom_input or custom_input.lower() == "-":
|
||||
custom_input = "No Answer"
|
||||
self.votes[str(user.id)]['answers'][self.survey_flags.index(choice)] = custom_input
|
||||
|
||||
self.votes[str(user.id)]['choices'].append(choice)
|
||||
self.votes[str(user.id)]['choices'] = list(set(self.votes[str(user.id)]['choices']))
|
||||
# else:
|
||||
@ -1175,12 +1447,9 @@ class Poll:
|
||||
|
||||
# commit
|
||||
await self.save_to_db()
|
||||
if not self.hide_count:
|
||||
asyncio.ensure_future(message.edit(embed=await self.generate_embed()))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
async def unvote(self, user, option, message, lock):
|
||||
if not await self.is_open():
|
||||
# refresh to show closed poll
|
||||
@ -1205,8 +1474,11 @@ class Poll:
|
||||
|
||||
if choice != 'invalid' and choice in self.votes[str(user.id)]['choices']:
|
||||
try:
|
||||
if choice in self.survey_flags and len(self.votes[str(user.id)]['answers']) == len(self.survey_flags):
|
||||
self.votes[str(user.id)]['answers'][self.survey_flags.index(choice)] = ''
|
||||
self.votes[str(user.id)]['choices'].remove(choice)
|
||||
await self.save_to_db()
|
||||
if not self.hide_count:
|
||||
asyncio.ensure_future(message.edit(embed=await self.generate_embed()))
|
||||
except ValueError:
|
||||
pass
|
||||
@ -62,7 +62,7 @@ async def on_ready():
|
||||
try:
|
||||
db_server_ids = [entry['_id'] async for entry in bot.db.config.find({}, {})]
|
||||
for server in bot.guilds:
|
||||
if server.id not in db_server_ids:
|
||||
if str(server.id) not in db_server_ids:
|
||||
# create new config entry
|
||||
await bot.db.config.update_one(
|
||||
{'_id': str(server.id)},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user