issue #3 adding "commandline" feature

This commit is contained in:
matnad 2019-02-14 19:05:38 +01:00
parent 3df015d132
commit a2be41dded
3 changed files with 95 additions and 61 deletions

View File

@ -52,7 +52,7 @@ class Poll:
self.short = str(uuid4())[0:23] self.short = str(uuid4())[0:23]
self.anonymous = False self.anonymous = False
self.reaction = True self.reaction = True
self.multiple_choice = False self.multiple_choice = 1
self.options_reaction = ['yes', 'no'] self.options_reaction = ['yes', 'no']
self.options_reaction_default = False self.options_reaction_default = False
# self.options_traditional = [] # self.options_traditional = []
@ -369,15 +369,15 @@ class Poll:
async def get_valid(in_reply): async def get_valid(in_reply):
if not in_reply: if not in_reply:
raise InvalidInput raise InvalidInput
is_true = ['yes', '1']
is_false = ['no', '0']
in_reply = self.sanitize_string(in_reply) in_reply = self.sanitize_string(in_reply)
if not in_reply: if not in_reply:
raise InvalidInput raise InvalidInput
elif in_reply.lower() in is_true: elif not in_reply.isdigit():
return True raise ExpectedInteger
elif in_reply.lower() in is_false: elif int(in_reply) > self.options_reaction.__len__():
return False raise OutOfRange
elif int(in_reply) <= self.options_reaction.__len__() >= 0:
return int(in_reply)
else: else:
raise InvalidInput raise InvalidInput
@ -387,13 +387,14 @@ class Poll:
except InputError: except InputError:
pass pass
text = ("**Should users be able to vote for multiple options?**\n" text = ("**How many options should the voters be able choose?**\n"
"\n" "\n"
"`0 - No`\n" "`0 - No Limit: Multiple Choice`\n"
"`1 - Yes`\n" "`1 - Single Choice`\n"
"`2+ - Specify exactly how many Choices`\n"
"\n" "\n"
"If you type `0` or `no`, a new vote will override the old vote. " "If the maximum choices are reached for a voter, they have to unvote an option before being able to "
"Otherwise the users can vote for as many options as they like.") "vote for a different one.")
message = await self.wizard_says(text) message = await self.wizard_says(text)
while True: while True:
@ -404,10 +405,14 @@ class Poll:
else: else:
reply = await self.get_user_reply() reply = await self.get_user_reply()
self.multiple_choice = await get_valid(reply) self.multiple_choice = await get_valid(reply)
await self.add_vaild(message, f'{"Yes" if self.multiple_choice else "No"}') await self.add_vaild(message, f'{self.multiple_choice if self.multiple_choice > 0 else "No Limit"}')
break break
except InvalidInput: except InvalidInput:
await self.add_error(message, '**You can only answer with `yes` | `1` or `no` | `0`!**') await self.add_error(message, '**Invalid Input**')
except ExpectedInteger:
await self.add_error(message, '**Enter a positive number**')
except OutOfRange:
await self.add_error(message, '**You can\'t have more choices than options.**')
async def set_options_reaction(self, force=None): async def set_options_reaction(self, force=None):
@ -842,7 +847,20 @@ class Poll:
self.short = d['short'] self.short = d['short']
self.anonymous = d['anonymous'] self.anonymous = d['anonymous']
self.reaction = d['reaction'] self.reaction = d['reaction']
self.multiple_choice = d['multiple_choice']
# backwards compatibility for multiple choice
if isinstance(d['multiple_choice'], bool):
if d['multiple_choice']:
self.multiple_choice = 0
else:
self.multiple_choice = 1
else:
try:
self.multiple_choice = int(d['multiple_choice'])
except ValueError:
logger.exception('Multiple Choice not an int or bool.')
self.multiple_choice = 0 # default
self.options_reaction = d['options_reaction'] self.options_reaction = d['options_reaction']
self.options_reaction_default = d['reaction_default'] self.options_reaction_default = d['reaction_default']
# self.options_traditional = d['options_traditional'] # self.options_traditional = d['options_traditional']
@ -936,8 +954,12 @@ class Poll:
if self.options_reaction_default: if self.options_reaction_default:
if await self.is_open(): if await self.is_open():
text = f'**Score** ' text = f'**Score** '
text += '*(Multiple Choice)*' if self.multiple_choice \ if self.multiple_choice == 0:
else '*(Single Choice)*' text += f'(Multiple Choice)'
elif self.multiple_choice == 1:
text += f'(Single Choice)'
else:
text += f'({self.multiple_choice} Choices)'
else: else:
text = f'**Final Score**' text = f'**Final Score**'
@ -949,10 +971,20 @@ class Poll:
embed.add_field(name='\u200b', value='\u200b', inline=False) embed.add_field(name='\u200b', value='\u200b', inline=False)
if await self.is_open(): if await self.is_open():
text = f'*Vote by adding reactions to the poll*. ' text = f'*Vote by adding reactions to the poll*. '
text += '*You can vote for multiple options.*' if self.multiple_choice \ if self.multiple_choice == 0:
else '*You have 1 vote, but can change it.*' text += '*You can vote for multiple options.*'
elif self.multiple_choice == 1:
text += '*You have 1 vote, but can change it.*'
else:
text += f'*You have {self.multiple_choice} choices and can change them.*'
else: else:
text = f'*Final Results of the {"multiple choice" if self.multiple_choice else "single choice"} Poll.*' text = f'*Final Results of the Poll *'
if self.multiple_choice == 0:
text += '*(Multiple Choice).*'
elif self.multiple_choice == 1:
text += '*(Single Choice).*'
else:
text += f'*(With up to {self.multiple_choice} choices).*'
embed = await self.add_field_custom(name='**Options**', value=text, embed=embed) embed = await self.add_field_custom(name='**Options**', value=text, embed=embed)
for i, r in enumerate(self.options_reaction): for i, r in enumerate(self.options_reaction):
embed = await self.add_field_custom( embed = await self.add_field_custom(
@ -1079,7 +1111,7 @@ class Poll:
return return
choice = 'invalid' choice = 'invalid'
already_voted = False refresh_poll = True
# get weight # get weight
weight = 1 weight = 1
@ -1103,18 +1135,27 @@ class Poll:
choice = AZ_EMOJIS.index(option) choice = AZ_EMOJIS.index(option)
if choice != 'invalid': if choice != 'invalid':
if self.multiple_choice: if self.multiple_choice != 1: # more than 1 choice (0 = no limit)
if choice in self.votes[user.id]['choices'] and self.anonymous: if choice in self.votes[user.id]['choices']:
# anonymous multiple choice -> can't unreact so we toggle with react if self.anonymous:
await self.unvote(user, option, message) # anonymous multiple choice -> can't unreact so we toggle with react
return await self.unvote(user, option, message)
self.votes[user.id]['choices'].append(choice) return
# if len(self.votes[user.id]['choices']) > len(set(self.votes[user.id]['choices'])): refresh_poll = False
# already_voted = True else:
self.votes[user.id]['choices'] = list(set(self.votes[user.id]['choices'])) if self.multiple_choice > 0 and self.votes[user.id]['choices'].__len__() >= self.multiple_choice:
say_text = f'You have reached the **maximum choices of {self.multiple_choice}** for this poll. ' \
f'Before you can vote again, you need to unvote one of your choices.'
embed = discord.Embed(title='', description=say_text, colour=SETTINGS.color)
embed.set_author(name='Pollmaster', icon_url=SETTINGS.author_icon)
await self.bot.send_message(user, embed=embed)
refresh_poll = False
else:
self.votes[user.id]['choices'].append(choice)
self.votes[user.id]['choices'] = list(set(self.votes[user.id]['choices']))
else: else:
if [choice] == self.votes[user.id]['choices']: if [choice] == self.votes[user.id]['choices']:
already_voted = True refresh_poll = False
if self.anonymous: if self.anonymous:
# undo anonymous vote # undo anonymous vote
await self.unvote(user, option, message) await self.unvote(user, option, message)
@ -1128,7 +1169,7 @@ class Poll:
await self.save_to_db() await self.save_to_db()
# refresh # refresh
if not already_voted: if refresh_poll:
# edit message if there is a real change # edit message if there is a real change
await self.bot.edit_message(message, embed=await self.generate_embed()) await self.bot.edit_message(message, embed=await self.generate_embed())
@ -1145,21 +1186,20 @@ class Poll:
if str(user.id) not in self.votes: return if str(user.id) not in self.votes: return
choice = 'invalid' choice = 'invalid'
if self.reaction: if self.options_reaction_default:
if self.options_reaction_default: if option in self.options_reaction:
if option in self.options_reaction: choice = self.options_reaction.index(option)
choice = self.options_reaction.index(option) else:
else: if option in AZ_EMOJIS:
if option in AZ_EMOJIS: choice = AZ_EMOJIS.index(option)
choice = AZ_EMOJIS.index(option)
if choice != 'invalid' and choice in self.votes[user.id]['choices']: if choice != 'invalid' and choice in self.votes[user.id]['choices']:
try: try:
self.votes[user.id]['choices'].remove(choice) self.votes[user.id]['choices'].remove(choice)
await self.save_to_db() await self.save_to_db()
await self.bot.edit_message(message, embed=await self.generate_embed()) await self.bot.edit_message(message, embed=await self.generate_embed())
except ValueError: except ValueError:
pass pass
async def has_required_role(self, user): async def has_required_role(self, user):
return not set([r.name for r in user.roles]).isdisjoint(self.roles) return not set([r.name for r in user.roles]).isdisjoint(self.roles)

View File

@ -266,11 +266,11 @@ class PollControls:
parser.add_argument('-question', '-q') parser.add_argument('-question', '-q')
parser.add_argument('-label', '-l', default=str(await generate_word(self.bot, server.id))) parser.add_argument('-label', '-l', default=str(await generate_word(self.bot, server.id)))
parser.add_argument('-options', '-o') parser.add_argument('-options', '-o')
parser.add_argument('-multiple_choice', '-mc', default='1')
parser.add_argument('-roles', '-r', default='all') parser.add_argument('-roles', '-r', default='all')
parser.add_argument('-weights', '-w', default='none') parser.add_argument('-weights', '-w', default='none')
parser.add_argument('-duration', '-d', default='0') parser.add_argument('-duration', '-d', default='0')
parser.add_argument('-anonymous', '-a', action="store_true") parser.add_argument('-anonymous', '-a', action="store_true")
parser.add_argument('-multiple_choice', '-mc', action="store_true")
helpstring = parser.format_help() helpstring = parser.format_help()
helpstring = helpstring.replace("pollmaster.py", f"{pre}cmd ") helpstring = helpstring.replace("pollmaster.py", f"{pre}cmd ")
@ -296,8 +296,8 @@ class PollControls:
await poll.set_name(force=args.question) await poll.set_name(force=args.question)
await poll.set_short(force=args.label) await poll.set_short(force=args.label)
await poll.set_anonymous(force=f'{"yes" if args.anonymous else "no"}') await poll.set_anonymous(force=f'{"yes" if args.anonymous else "no"}')
await poll.set_multiple_choice(force=f'{"yes" if args.multiple_choice else "no"}')
await poll.set_options_reaction(force=args.options) 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_roles(force=args.roles)
await poll.set_weights(force=args.weights) await poll.set_weights(force=args.weights)
await poll.set_duration(force=args.duration) await poll.set_duration(force=args.duration)
@ -318,8 +318,8 @@ class PollControls:
await poll.set_name(force=cmd) await poll.set_name(force=cmd)
await poll.set_short(force=str(await generate_word(self.bot, server.id))) await poll.set_short(force=str(await generate_word(self.bot, server.id)))
await poll.set_anonymous(force='no') await poll.set_anonymous(force='no')
await poll.set_multiple_choice(force='no')
await poll.set_options_reaction() await poll.set_options_reaction()
await poll.set_multiple_choice(force='1')
await poll.set_roles(force='all') await poll.set_roles(force='all')
await poll.set_weights(force='none') await poll.set_weights(force='none')
await poll.set_duration(force='0') await poll.set_duration(force='0')
@ -340,11 +340,8 @@ class PollControls:
await poll.set_short() await poll.set_short()
await poll.set_preparation() await poll.set_preparation()
await poll.set_anonymous() await poll.set_anonymous()
await poll.set_options_reaction()
await poll.set_multiple_choice() await poll.set_multiple_choice()
if poll.reaction:
await poll.set_options_reaction()
else:
await poll.set_options_traditional()
await poll.set_roles() await poll.set_roles()
await poll.set_weights() await poll.set_weights()
await poll.set_duration() await poll.set_duration()
@ -364,11 +361,8 @@ class PollControls:
await poll.set_name(force=cmd) await poll.set_name(force=cmd)
await poll.set_short() await poll.set_short()
await poll.set_anonymous() await poll.set_anonymous()
await poll.set_options_reaction()
await poll.set_multiple_choice() await poll.set_multiple_choice()
if poll.reaction:
await poll.set_options_reaction()
else:
await poll.set_options_traditional()
await poll.set_roles() await poll.set_roles()
await poll.set_weights() await poll.set_weights()
await poll.set_duration() await poll.set_duration()
@ -547,7 +541,7 @@ class PollControls:
if p.anonymous: if p.anonymous:
# immediately remove reaction and to be safe, remove all reactions # immediately remove reaction and to be safe, remove all reactions
await self.bot.remove_reaction(message, emoji, user) await self.bot.remove_reaction(message, emoji, user)
elif not p.multiple_choice: elif p.multiple_choice == 1:
# remove all other reactions # remove all other reactions
for r in message.reactions: for r in message.reactions:
if r.emoji and r.emoji != emoji: if r.emoji and r.emoji != emoji:

View File

@ -6,9 +6,9 @@ from essentials.secrets import SECRETS
class Settings: class Settings:
def __init__(self): def __init__(self):
self.color = discord.Colour(int('7289da', 16)) self.color = discord.Colour(int('7289da', 16))
self.title_icon = "http://mnadler.ch/img/tag.png" self.title_icon = "https://i.imgur.com/vtLsAl8.jpg" #PM
self.author_icon = "http://mnadler.ch/img/tag.jpg" self.author_icon = "https://i.imgur.com/TYbBtwB.jpg" #tag
self.report_icon = "http://mnadler.ch/img/report.png" self.report_icon = "https://i.imgur.com/YksGRLN.png" #report
self.owner_id = 117687652278468610 self.owner_id = 117687652278468610
self.msg_errors = False self.msg_errors = False
self.log_errors = True self.log_errors = True