Merge pull request #5 from matnad/issue_3_4
Solve issues 3, 4, 6 and implement the info (❔) feature
This commit is contained in:
commit
bf5797ea76
@ -1,3 +1,10 @@
|
|||||||
|
# Changelog for Version 2.1
|
||||||
|
|
||||||
|
## New features
|
||||||
|
- React to a poll with ❔ to get personalised info
|
||||||
|
- Added back the command line feature from version 1. Type *pm!cmd help* to get started
|
||||||
|
- Multiple choice is no longer a flag, but a number of how many options each voter can choose
|
||||||
|
|
||||||
# Changelog for Version 2.0
|
# Changelog for Version 2.0
|
||||||
|
|
||||||
## TL;DR
|
## TL;DR
|
||||||
|
|||||||
10
cogs/help.py
10
cogs/help.py
@ -49,7 +49,7 @@ class Help:
|
|||||||
if page == '🏠':
|
if page == '🏠':
|
||||||
## POLL CREATION SHORT
|
## POLL CREATION SHORT
|
||||||
embed.add_field(name='🆕 Making New Polls',
|
embed.add_field(name='🆕 Making New Polls',
|
||||||
value=f'`{pre}quick` | `{pre}new` | `{pre}prepare`', inline=False)
|
value=f'`{pre}quick` | `{pre}new` | `{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='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='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?`',
|
# embed.add_field(name='Examples', value=f'Examples: `{pre}new` | `{pre}quick What is the greenest color?`',
|
||||||
@ -108,6 +108,14 @@ class Help:
|
|||||||
f'and/or if you would like to manually `{pre}activate` it. '
|
f'and/or if you would like to manually `{pre}activate` it. '
|
||||||
'Perfect if you are preparing for a team meeting!',
|
'Perfect if you are preparing for a team meeting!',
|
||||||
inline=False)
|
inline=False)
|
||||||
|
embed.add_field(name=f'🔹 **-Advanced- Commandline:** `{pre}cmd <args>`',
|
||||||
|
value=f'For the full syntax type `{pre}cmd help`\n'
|
||||||
|
f'Similar to version 1 of the bot, with this command you can create a poll in one message. '
|
||||||
|
f'Pass all the options you need via command line arguments, the rest will be set to '
|
||||||
|
f'default values. The wizard will step in for invalid arguments.\n'
|
||||||
|
f'Example: `{pre}cmd -q "Which colors?" -l colors -o "green, blue, red" -mc -a`',
|
||||||
|
inline=False)
|
||||||
|
|
||||||
elif page == '🔍':
|
elif page == '🔍':
|
||||||
embed.add_field(name='🔍 Show Polls',
|
embed.add_field(name='🔍 Show Polls',
|
||||||
value='All users can display and list polls, with the exception of prepared polls. '
|
value='All users can display and list polls, with the exception of prepared polls. '
|
||||||
|
|||||||
240
cogs/poll.py
240
cogs/poll.py
@ -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 = []
|
||||||
@ -165,7 +165,11 @@ class Poll:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
reply = await self.get_user_reply()
|
if force:
|
||||||
|
reply = force
|
||||||
|
force = None
|
||||||
|
else:
|
||||||
|
reply = await self.get_user_reply()
|
||||||
self.name = await get_valid(reply)
|
self.name = await get_valid(reply)
|
||||||
await self.add_vaild(message, self.name)
|
await self.add_vaild(message, self.name)
|
||||||
break
|
break
|
||||||
@ -203,7 +207,11 @@ class Poll:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
reply = await self.get_user_reply()
|
if force:
|
||||||
|
reply = force
|
||||||
|
force = None
|
||||||
|
else:
|
||||||
|
reply = await self.get_user_reply()
|
||||||
self.short = await get_valid(reply)
|
self.short = await get_valid(reply)
|
||||||
await self.add_vaild(message, self.short)
|
await self.add_vaild(message, self.short)
|
||||||
break
|
break
|
||||||
@ -263,7 +271,11 @@ class Poll:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
reply = await self.get_user_reply()
|
if force:
|
||||||
|
reply = force
|
||||||
|
force = None
|
||||||
|
else:
|
||||||
|
reply = await self.get_user_reply()
|
||||||
dt = await get_valid(reply)
|
dt = await get_valid(reply)
|
||||||
self.activation = dt
|
self.activation = dt
|
||||||
if self.activation == 0:
|
if self.activation == 0:
|
||||||
@ -315,7 +327,11 @@ class Poll:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
reply = await self.get_user_reply()
|
if force:
|
||||||
|
reply = force
|
||||||
|
force = None
|
||||||
|
else:
|
||||||
|
reply = await self.get_user_reply()
|
||||||
self.anonymous = await get_valid(reply)
|
self.anonymous = await get_valid(reply)
|
||||||
await self.add_vaild(message, f'{"Yes" if self.anonymous else "No"}')
|
await self.add_vaild(message, f'{"Yes" if self.anonymous else "No"}')
|
||||||
break
|
break
|
||||||
@ -353,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
|
||||||
|
|
||||||
@ -371,23 +387,32 @@ 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:
|
||||||
try:
|
try:
|
||||||
reply = await self.get_user_reply()
|
if force:
|
||||||
|
reply = force
|
||||||
|
force = None
|
||||||
|
else:
|
||||||
|
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):
|
||||||
@ -442,7 +467,7 @@ class Poll:
|
|||||||
"**1** - :white_check_mark: :negative_squared_cross_mark:\n"
|
"**1** - :white_check_mark: :negative_squared_cross_mark:\n"
|
||||||
"**2** - :thumbsup: :zipper_mouth: :thumbsdown:\n"
|
"**2** - :thumbsup: :zipper_mouth: :thumbsdown:\n"
|
||||||
"**3** - :heart_eyes: :thumbsup: :zipper_mouth: :thumbsdown: :nauseated_face:\n"
|
"**3** - :heart_eyes: :thumbsup: :zipper_mouth: :thumbsdown: :nauseated_face:\n"
|
||||||
"**4** - in favour, against, abstain\n"
|
"**4** - in favour, against, abstaining\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Example for custom options:\n"
|
"Example for custom options:\n"
|
||||||
"**apple juice, banana ice cream, kiwi slices** ")
|
"**apple juice, banana ice cream, kiwi slices** ")
|
||||||
@ -450,7 +475,11 @@ class Poll:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
reply = await self.get_user_reply()
|
if force:
|
||||||
|
reply = force
|
||||||
|
force = None
|
||||||
|
else:
|
||||||
|
reply = await self.get_user_reply()
|
||||||
options = await get_valid(reply)
|
options = await get_valid(reply)
|
||||||
self.options_reaction_default = False
|
self.options_reaction_default = False
|
||||||
if isinstance(options, int):
|
if isinstance(options, int):
|
||||||
@ -481,7 +510,7 @@ class Poll:
|
|||||||
if split.__len__() == 1 and split[0] in ['0', 'all', 'everyone']:
|
if split.__len__() == 1 and split[0] in ['0', 'all', 'everyone']:
|
||||||
return ['@everyone']
|
return ['@everyone']
|
||||||
|
|
||||||
if n_roles <= 20:
|
if n_roles <= 20 and force is None:
|
||||||
if not all([r.isdigit() for r in split]):
|
if not all([r.isdigit() for r in split]):
|
||||||
raise ExpectedInteger
|
raise ExpectedInteger
|
||||||
elif any([int(r) > n_roles for r in split]):
|
elif any([int(r) > n_roles for r in split]):
|
||||||
@ -527,7 +556,11 @@ class Poll:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
reply = await self.get_user_reply()
|
if force:
|
||||||
|
reply = force
|
||||||
|
force = None
|
||||||
|
else:
|
||||||
|
reply = await self.get_user_reply()
|
||||||
self.roles = await get_valid(reply, roles)
|
self.roles = await get_valid(reply, roles)
|
||||||
await self.add_vaild(message, f'{", ".join(self.roles)}')
|
await self.add_vaild(message, f'{", ".join(self.roles)}')
|
||||||
break
|
break
|
||||||
@ -540,43 +573,6 @@ class Poll:
|
|||||||
except InvalidRoles as e:
|
except InvalidRoles as e:
|
||||||
await self.add_error(message, f'**The following roles are invalid: {e.roles}**')
|
await self.add_error(message, f'**The following roles are invalid: {e.roles}**')
|
||||||
|
|
||||||
# async def set_options_traditional(self, force=None):
|
|
||||||
# '''Currently not used as everything is reaction based'''
|
|
||||||
# if force is not None:
|
|
||||||
# self.options_traditional = force
|
|
||||||
# return
|
|
||||||
# if self.stopped: return
|
|
||||||
# text = """**Next you chose from the possible set of options/answers for your poll.**
|
|
||||||
# Type the corresponding number or type your own options, separated by commas.
|
|
||||||
#
|
|
||||||
# **1** - yes, no
|
|
||||||
# **2** - in favour, against, abstain
|
|
||||||
# **3** - love it, like it, don't care, meh, hate it
|
|
||||||
#
|
|
||||||
# If you write your own options they will be listed and can be voted for.
|
|
||||||
# To use your custom options type them like this:
|
|
||||||
# **apple juice, banana ice cream, kiwi slices**"""
|
|
||||||
# message = await self.wizard_says(text)
|
|
||||||
#
|
|
||||||
# reply = ''
|
|
||||||
# while reply == '' or (reply.split(",").__len__() < 2 and reply not in ['1', '2', '3']) \
|
|
||||||
# or (reply.split(",").__len__() > 99 and reply not in ['1', '2', '3']):
|
|
||||||
# if reply != '':
|
|
||||||
# await self.add_error(message,
|
|
||||||
# '**Invalid entry. Type `1` `2` or `3` or a comma separated list (max. 99 options).**')
|
|
||||||
# reply = await self.get_user_reply()
|
|
||||||
# if self.stopped: break
|
|
||||||
#
|
|
||||||
# if reply == '1':
|
|
||||||
# self.options_traditional = ['yes, no']
|
|
||||||
# elif reply == '2':
|
|
||||||
# self.options_traditional = ['in favour', 'against', 'abstain']
|
|
||||||
# elif reply == '3':
|
|
||||||
# self.options_traditional = ['love it', 'like it', 'don\'t care', 'meh', 'hate it']
|
|
||||||
# else:
|
|
||||||
# self.options_traditional = [r.strip() for r in reply.split(",")]
|
|
||||||
# return self.options_traditional
|
|
||||||
|
|
||||||
async def set_weights(self, force=None):
|
async def set_weights(self, force=None):
|
||||||
"""Set role weights for the poll."""
|
"""Set role weights for the poll."""
|
||||||
async def get_valid(in_reply, server_roles):
|
async def get_valid(in_reply, server_roles):
|
||||||
@ -623,7 +619,11 @@ class Poll:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
reply = await self.get_user_reply()
|
if force:
|
||||||
|
reply = force
|
||||||
|
force = None
|
||||||
|
else:
|
||||||
|
reply = await self.get_user_reply()
|
||||||
w_n = await get_valid(reply, self.server.roles)
|
w_n = await get_valid(reply, self.server.roles)
|
||||||
self.weights_roles = w_n[0]
|
self.weights_roles = w_n[0]
|
||||||
self.weights_numbers = w_n[1]
|
self.weights_numbers = w_n[1]
|
||||||
@ -686,7 +686,11 @@ class Poll:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
reply = await self.get_user_reply()
|
if force:
|
||||||
|
reply = force
|
||||||
|
force = None
|
||||||
|
else:
|
||||||
|
reply = await self.get_user_reply()
|
||||||
dt = await get_valid(reply)
|
dt = await get_valid(reply)
|
||||||
self.duration = dt
|
self.duration = dt
|
||||||
if self.duration == 0:
|
if self.duration == 0:
|
||||||
@ -705,7 +709,6 @@ class Poll:
|
|||||||
def finalize(self):
|
def finalize(self):
|
||||||
self.time_created = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
|
self.time_created = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
|
||||||
|
|
||||||
|
|
||||||
async def to_dict(self):
|
async def to_dict(self):
|
||||||
if self.channel is None:
|
if self.channel is None:
|
||||||
cid = 0
|
cid = 0
|
||||||
@ -844,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']
|
||||||
@ -938,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**'
|
||||||
|
|
||||||
@ -951,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(
|
||||||
@ -965,7 +995,7 @@ class Poll:
|
|||||||
# else:
|
# else:
|
||||||
# embed = await self.add_field_custom(name='**Options**', value=', '.join(self.get_options()), embed=embed)
|
# embed = await self.add_field_custom(name='**Options**', value=', '.join(self.get_options()), embed=embed)
|
||||||
|
|
||||||
embed.set_footer(text='bot is in development')
|
# embed.set_footer(text='bot is in development')
|
||||||
|
|
||||||
return embed
|
return embed
|
||||||
|
|
||||||
@ -981,6 +1011,7 @@ class Poll:
|
|||||||
msg,
|
msg,
|
||||||
r
|
r
|
||||||
)
|
)
|
||||||
|
await self.bot.add_reaction(msg, '❔')
|
||||||
return msg
|
return msg
|
||||||
else:
|
else:
|
||||||
for i, r in enumerate(self.options_reaction):
|
for i, r in enumerate(self.options_reaction):
|
||||||
@ -988,18 +1019,14 @@ class Poll:
|
|||||||
msg,
|
msg,
|
||||||
AZ_EMOJIS[i]
|
AZ_EMOJIS[i]
|
||||||
)
|
)
|
||||||
|
await self.bot.add_reaction(msg, '❔')
|
||||||
return msg
|
return msg
|
||||||
elif not await self.is_open():
|
elif not await self.is_open():
|
||||||
|
await self.bot.add_reaction(msg, '❔')
|
||||||
await self.bot.add_reaction(msg, '📎')
|
await self.bot.add_reaction(msg, '📎')
|
||||||
else:
|
else:
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
# def get_options(self):
|
|
||||||
# if self.reaction:
|
|
||||||
# return self.options_reaction
|
|
||||||
# else:
|
|
||||||
# return self.options_traditional
|
|
||||||
|
|
||||||
def get_duration_with_tz(self):
|
def get_duration_with_tz(self):
|
||||||
if self.duration == 0:
|
if self.duration == 0:
|
||||||
return 0
|
return 0
|
||||||
@ -1077,7 +1104,6 @@ class Poll:
|
|||||||
else:
|
else:
|
||||||
return sum([1 for c in [u for u in self.votes] if option in self.votes[c]['choices']])
|
return sum([1 for c in [u for u in self.votes] if option in self.votes[c]['choices']])
|
||||||
|
|
||||||
|
|
||||||
async def vote(self, user, option, message):
|
async def vote(self, user, option, message):
|
||||||
if not await self.is_open():
|
if not await self.is_open():
|
||||||
# refresh to show closed poll
|
# refresh to show closed poll
|
||||||
@ -1088,7 +1114,7 @@ class Poll:
|
|||||||
return
|
return
|
||||||
|
|
||||||
choice = 'invalid'
|
choice = 'invalid'
|
||||||
already_voted = False
|
refresh_poll = True
|
||||||
|
|
||||||
# get weight
|
# get weight
|
||||||
weight = 1
|
weight = 1
|
||||||
@ -1112,18 +1138,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)
|
||||||
@ -1137,7 +1172,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())
|
||||||
|
|
||||||
@ -1154,21 +1189,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)
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
|
import argparse
|
||||||
import copy
|
import copy
|
||||||
|
import datetime
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import shlex
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
|
import pytz
|
||||||
|
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
||||||
|
from utils.misc import CustomFormatter
|
||||||
from .poll import Poll
|
from .poll import Poll
|
||||||
from utils.paginator import embed_list_paginated
|
from utils.paginator import embed_list_paginated
|
||||||
from essentials.multi_server import get_server_pre, ask_for_server, ask_for_channel
|
from essentials.multi_server import get_server_pre, ask_for_server, ask_for_channel
|
||||||
@ -34,14 +41,14 @@ class PollControls:
|
|||||||
|
|
||||||
async def say_error(self, ctx, error_text, footer_text=None):
|
async def say_error(self, ctx, error_text, footer_text=None):
|
||||||
embed = discord.Embed(title='', description=error_text, colour=SETTINGS.color)
|
embed = discord.Embed(title='', description=error_text, colour=SETTINGS.color)
|
||||||
embed.set_author(name='Error', icon_url=SETTINGS.title_icon)
|
embed.set_author(name='Error', icon_url=SETTINGS.author_icon)
|
||||||
if footer_text is not None:
|
if footer_text is not None:
|
||||||
embed.set_footer(text=footer_text)
|
embed.set_footer(text=footer_text)
|
||||||
await self.bot.say(embed=embed)
|
await self.bot.say(embed=embed)
|
||||||
|
|
||||||
async def say_embed(self, ctx, say_text='', title='Pollmaster', footer_text=None):
|
async def say_embed(self, ctx, say_text='', title='Pollmaster', footer_text=None):
|
||||||
embed = discord.Embed(title='', description=say_text, colour=SETTINGS.color)
|
embed = discord.Embed(title='', description=say_text, colour=SETTINGS.color)
|
||||||
embed.set_author(name=title, icon_url=SETTINGS.title_icon)
|
embed.set_author(name=title, icon_url=SETTINGS.author_icon)
|
||||||
if footer_text is not None:
|
if footer_text is not None:
|
||||||
embed.set_footer(text=footer_text)
|
embed.set_footer(text=footer_text)
|
||||||
await self.bot.say(embed=embed)
|
await self.bot.say(embed=embed)
|
||||||
@ -217,12 +224,12 @@ class PollControls:
|
|||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
def item_fct(item):
|
def item_fct(i,item):
|
||||||
return f':black_small_square: **{item["short"]}**: {item["name"]}'
|
return f':black_small_square: **{item["short"]}**: {item["name"]}'
|
||||||
|
|
||||||
title = f' Listing {short} polls'
|
title = f' Listing {short} polls'
|
||||||
embed = discord.Embed(title='', description='', colour=SETTINGS.color)
|
embed = discord.Embed(title='', description='', colour=SETTINGS.color)
|
||||||
embed.set_author(name=title, icon_url=SETTINGS.title_icon)
|
embed.set_author(name=title, icon_url=SETTINGS.author_icon)
|
||||||
# await self.bot.say(embed=await self.embed_list_paginated(polls, item_fct, embed))
|
# await self.bot.say(embed=await self.embed_list_paginated(polls, item_fct, embed))
|
||||||
# msg = await self.embed_list_paginated(ctx, polls, item_fct, embed, per_page=8)
|
# msg = await self.embed_list_paginated(ctx, polls, item_fct, embed, per_page=8)
|
||||||
pre = await get_server_pre(self.bot, server)
|
pre = await get_server_pre(self.bot, server)
|
||||||
@ -242,73 +249,132 @@ class PollControls:
|
|||||||
footer = f'Type {pre}show to display all polls'
|
footer = f'Type {pre}show to display all polls'
|
||||||
await self.say_error(ctx, error, footer)
|
await self.say_error(ctx, error, footer)
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
async def cmd(self, ctx, *, cmd=None):
|
||||||
|
'''The old, command style way paired with the wizard.'''
|
||||||
|
server = await ask_for_server(self.bot, ctx.message)
|
||||||
|
if not server:
|
||||||
|
return
|
||||||
|
pre = await get_server_pre(self.bot, server)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
try:
|
||||||
|
args = parser.parse_args(cmds)
|
||||||
|
except SystemExit:
|
||||||
|
await self.say_error(ctx, error_text=helpstring)
|
||||||
|
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()
|
||||||
|
|
||||||
|
|
||||||
@commands.command(pass_context=True)
|
@commands.command(pass_context=True)
|
||||||
async def quick(self, ctx, *, cmd=None):
|
async def quick(self, ctx, *, cmd=None):
|
||||||
'''Create a quick poll with just a question and some options. Parameters: <Question> (optional)'''
|
'''Create a quick poll with just a question and some options. Parameters: <Question> (optional)'''
|
||||||
|
server = await ask_for_server(self.bot, ctx.message)
|
||||||
|
if not server:
|
||||||
|
return
|
||||||
|
|
||||||
async def route(poll):
|
async def route(poll):
|
||||||
await poll.set_name(force=cmd)
|
await poll.set_name(force=cmd)
|
||||||
await poll.set_short(force=str(await generate_word(self.bot, ctx.message.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')
|
||||||
|
|
||||||
poll = await self.wizard(ctx, route)
|
poll = await self.wizard(ctx, route, server)
|
||||||
if poll:
|
if poll:
|
||||||
await poll.post_embed()
|
await poll.post_embed()
|
||||||
|
|
||||||
@commands.command(pass_context=True)
|
@commands.command(pass_context=True)
|
||||||
async def prepare(self, ctx, *, cmd=None):
|
async def prepare(self, ctx, *, cmd=None):
|
||||||
'''Prepare a poll to use later. Parameters: <Question> (optional) '''
|
'''Prepare a poll to use later. Parameters: <Question> (optional) '''
|
||||||
|
server = await ask_for_server(self.bot, ctx.message)
|
||||||
|
if not server:
|
||||||
|
return
|
||||||
|
|
||||||
async def route(poll):
|
async def route(poll):
|
||||||
await poll.set_name(force=cmd)
|
await poll.set_name(force=cmd)
|
||||||
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()
|
||||||
|
|
||||||
poll = await self.wizard(ctx, route)
|
poll = await self.wizard(ctx, route, server)
|
||||||
if poll:
|
if poll:
|
||||||
await poll.post_embed(destination=ctx.message.author)
|
await poll.post_embed(destination=ctx.message.author)
|
||||||
|
|
||||||
@commands.command(pass_context=True)
|
@commands.command(pass_context=True)
|
||||||
async def new(self, ctx, *, cmd=None):
|
async def new(self, ctx, *, cmd=None):
|
||||||
'''Start the poll wizard to create a new poll step by step. Parameters: <Question> (optional) '''
|
'''Start the poll wizard to create a new poll step by step. Parameters: <Question> (optional) '''
|
||||||
|
server = await ask_for_server(self.bot, ctx.message)
|
||||||
|
if not server:
|
||||||
|
return
|
||||||
|
|
||||||
async def route(poll):
|
async def route(poll):
|
||||||
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()
|
||||||
|
|
||||||
poll = await self.wizard(ctx, route)
|
poll = await self.wizard(ctx, route, server)
|
||||||
if poll:
|
if poll:
|
||||||
await poll.post_embed()
|
await poll.post_embed()
|
||||||
|
|
||||||
# The Wizard!
|
# The Wizard!
|
||||||
async def wizard(self, ctx, route):
|
async def wizard(self, ctx, route, server):
|
||||||
server = await ask_for_server(self.bot, ctx.message)
|
|
||||||
if not server:
|
|
||||||
return
|
|
||||||
|
|
||||||
channel = await ask_for_channel(self.bot, server, ctx.message)
|
channel = await ask_for_channel(self.bot, server, ctx.message)
|
||||||
if not channel:
|
if not channel:
|
||||||
return
|
return
|
||||||
@ -460,8 +526,67 @@ class PollControls:
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# no rights, terminate function
|
# info
|
||||||
member = server.get_member(user_id)
|
member = server.get_member(user_id)
|
||||||
|
if emoji == '❔':
|
||||||
|
is_open = await p.is_open()
|
||||||
|
embed = discord.Embed(title=f"Info for the {'CLOSED ' if not is_open else ''}poll \"{p.name}\"",
|
||||||
|
description='', color=SETTINGS.color)
|
||||||
|
embed.set_author(name=f" >> {p.short}", icon_url=SETTINGS.author_icon)
|
||||||
|
|
||||||
|
# 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?"}',
|
||||||
|
value=f'{"✅" if vote_rights else "❎"}', inline=False)
|
||||||
|
|
||||||
|
# edit rights
|
||||||
|
edit_rights = False
|
||||||
|
if str(member.id) == str(p.author):
|
||||||
|
edit_rights = True
|
||||||
|
elif member.server_permissions.manage_server:
|
||||||
|
edit_rights = True
|
||||||
|
else:
|
||||||
|
result = await self.bot.db.config.find_one({'_id': str(server.id)})
|
||||||
|
if result and result.get('admin_role') in [r.name for r in member.roles]:
|
||||||
|
edit_rights = True
|
||||||
|
embed.add_field(name='Can you manage the poll?', value=f'{"✅" if edit_rights else "❎"}', inline=False)
|
||||||
|
|
||||||
|
# choices
|
||||||
|
choices = 'You have not voted yet.' if vote_rights else 'You can\'t vote in this poll.'
|
||||||
|
if user.id in p.votes:
|
||||||
|
if p.votes[user.id]['choices'].__len__() > 0:
|
||||||
|
choices = ', '.join([p.options_reaction[c] for c in p.votes[user.id]['choices']])
|
||||||
|
embed.add_field(name=f'{"Your current votes (can be changed as long as the poll is open):" if is_open else "Your final votes:"}',
|
||||||
|
value=choices, inline=False)
|
||||||
|
|
||||||
|
# weight
|
||||||
|
if vote_rights:
|
||||||
|
weight = 1
|
||||||
|
if p.weights_roles.__len__() > 0:
|
||||||
|
valid_weights = [p.weights_numbers[p.weights_roles.index(r)] for r in
|
||||||
|
list(set([n.name for n in member.roles]).intersection(set(p.weights_roles)))]
|
||||||
|
if valid_weights.__len__() > 0:
|
||||||
|
weight = max(valid_weights)
|
||||||
|
else:
|
||||||
|
weight = 'You can\'t vote in this poll.'
|
||||||
|
embed.add_field(name='Weight of your votes:', value=weight, inline=False)
|
||||||
|
|
||||||
|
# time left
|
||||||
|
deadline = p.get_duration_with_tz()
|
||||||
|
if not is_open:
|
||||||
|
time_left = 'This poll is closed.'
|
||||||
|
elif deadline == 0:
|
||||||
|
time_left = 'Until manually closed.'
|
||||||
|
else:
|
||||||
|
time_left = str(deadline-datetime.datetime.utcnow().replace(tzinfo=pytz.utc)).split('.', 2)[0]
|
||||||
|
|
||||||
|
embed.add_field(name='Time left in the poll:', value=time_left, inline=False)
|
||||||
|
|
||||||
|
await self.bot.send_message(user, embed=embed)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Assume: User wants to vote with reaction
|
||||||
|
# no rights, terminate function
|
||||||
if not await p.has_required_role(member):
|
if not await p.has_required_role(member):
|
||||||
await self.bot.remove_reaction(message, emoji, user)
|
await self.bot.remove_reaction(message, emoji, user)
|
||||||
await self.bot.send_message(user, f'You are not allowed to vote in this poll. Only users with '
|
await self.bot.send_message(user, f'You are not allowed to vote in this poll. Only users with '
|
||||||
@ -477,7 +602,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:
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
|
|
||||||
from essentials.settings import SETTINGS
|
from essentials.settings import SETTINGS
|
||||||
|
from utils.paginator import embed_list_paginated
|
||||||
|
|
||||||
|
|
||||||
async def get_pre(bot, message):
|
async def get_pre(bot, message):
|
||||||
'''Gets the prefix for a message.'''
|
'''Gets the prefix for a message.'''
|
||||||
@ -107,13 +111,22 @@ async def ask_for_channel(bot, server, message):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
# otherwise ask for a channel
|
# otherwise ask for a channel
|
||||||
text = 'Polls are bound to a specific channel on a server. Please select the channel for this poll by typing the corresponding number.\n'
|
|
||||||
i = 1
|
i = 1
|
||||||
|
text = 'Polls are bound to a specific channel on a server. Please select the channel for this poll by typing the corresponding number.\n'
|
||||||
for name in [c.name for c in channel_list]:
|
for name in [c.name for c in channel_list]:
|
||||||
text += f'\n**{i}** - {name}'
|
to_add = f'\n**{i}** - {name}'
|
||||||
i += 1
|
|
||||||
|
# check if length doesn't exceed allowed maximum or split it into multiple messages
|
||||||
|
if text.__len__() + to_add.__len__() > 2048:
|
||||||
|
embed = discord.Embed(title="Select a channel", description=text, color=SETTINGS.color)
|
||||||
|
await bot.say(embed=embed)
|
||||||
|
text = 'Polls are bound to a specific channel on a server. Please select the channel for this poll by typing the corresponding number.\n'
|
||||||
|
else:
|
||||||
|
text += to_add
|
||||||
|
i += 1
|
||||||
|
|
||||||
embed = discord.Embed(title="Select a channel", description=text, color=SETTINGS.color)
|
embed = discord.Embed(title="Select a channel", description=text, color=SETTINGS.color)
|
||||||
server_msg = await bot.say(embed=embed)
|
await bot.say(embed=embed)
|
||||||
|
|
||||||
valid_reply = False
|
valid_reply = False
|
||||||
nr = 1
|
nr = 1
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -53,7 +53,7 @@ async def on_ready():
|
|||||||
bot.db = mongo.pollmaster
|
bot.db = mongo.pollmaster
|
||||||
bot.session = aiohttp.ClientSession()
|
bot.session = aiohttp.ClientSession()
|
||||||
print(bot.db)
|
print(bot.db)
|
||||||
await bot.change_presence(game=discord.Game(name=f'V2 IS HERE >> pm!help'))
|
await bot.change_presence(game=discord.Game(name=f'pm!help - v2.1 is live!'))
|
||||||
|
|
||||||
# check discord server configs
|
# check discord server configs
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
aiohttp==3.5.4
|
aiohttp==1.0.5
|
||||||
async-timeout==3.0.1
|
async-timeout==3.0.1
|
||||||
attrs==18.2.0
|
attrs==18.2.0
|
||||||
beautifulsoup4==4.7.1
|
beautifulsoup4==4.7.1
|
||||||
|
|||||||
@ -1,6 +1,35 @@
|
|||||||
|
import argparse
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
|
|
||||||
|
|
||||||
|
class CustomFormatter(argparse.RawTextHelpFormatter):
|
||||||
|
def _format_action_invocation(self, action):
|
||||||
|
if not action.option_strings:
|
||||||
|
metavar, = self._metavar_formatter(action, action.dest)(1)
|
||||||
|
return metavar
|
||||||
|
else:
|
||||||
|
parts = []
|
||||||
|
# if the Optional doesn't take a value, format is:
|
||||||
|
# -s, --long
|
||||||
|
if action.nargs == 0:
|
||||||
|
parts.extend(action.option_strings)
|
||||||
|
|
||||||
|
# if the Optional takes a value, format is:
|
||||||
|
# -s ARGS, --long ARGS
|
||||||
|
# change to
|
||||||
|
# -s, --long ARGS
|
||||||
|
else:
|
||||||
|
default = action.dest.upper()
|
||||||
|
args_string = self._format_args(action, default)
|
||||||
|
for option_string in action.option_strings:
|
||||||
|
# parts.append('%s %s' % (option_string, args_string))
|
||||||
|
parts.append('%s' % option_string)
|
||||||
|
parts[-1] += ' %s' % args_string
|
||||||
|
return ', '.join(parts)
|
||||||
|
|
||||||
|
|
||||||
def possible_timezones(tz_offset, common_only=True):
|
def possible_timezones(tz_offset, common_only=True):
|
||||||
# pick one of the timezone collections
|
# pick one of the timezone collections
|
||||||
timezones = pytz.common_timezones if common_only else pytz.all_timezones
|
timezones = pytz.common_timezones if common_only else pytz.all_timezones
|
||||||
|
|||||||
@ -4,8 +4,9 @@ async def embed_list_paginated(bot, pre, items, item_fct, base_embed, footer_pre
|
|||||||
# generate list
|
# generate list
|
||||||
embed.title = f'{items.__len__()} entries'
|
embed.title = f'{items.__len__()} entries'
|
||||||
text = '\n'
|
text = '\n'
|
||||||
for item in items[start:start+per_page]:
|
for i,item in enumerate(items[start:start+per_page]):
|
||||||
text += item_fct(item) + '\n'
|
j = i+start
|
||||||
|
text += item_fct(j,item) + '\n'
|
||||||
embed.description = text
|
embed.description = text
|
||||||
|
|
||||||
# footer text
|
# footer text
|
||||||
@ -21,7 +22,8 @@ async def embed_list_paginated(bot, pre, items, item_fct, base_embed, footer_pre
|
|||||||
# post / edit message
|
# post / edit message
|
||||||
if msg is not None:
|
if msg is not None:
|
||||||
await bot.edit_message(msg, embed=embed)
|
await bot.edit_message(msg, embed=embed)
|
||||||
await bot.clear_reactions(msg)
|
if str(msg.channel.type) != 'private':
|
||||||
|
await bot.clear_reactions(msg)
|
||||||
else:
|
else:
|
||||||
msg = await bot.say(embed=embed)
|
msg = await bot.say(embed=embed)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user