v 2.0.0
This commit is contained in:
parent
67ad573dd6
commit
d94d0b976a
@ -1,3 +1,5 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
|
|
||||||
@ -74,4 +76,6 @@ class Config:
|
|||||||
await self.bot.say(f'Server role `{role}` not found.')
|
await self.bot.say(f'Server role `{role}` not found.')
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot):
|
||||||
|
global logger
|
||||||
|
logger = logging.getLogger('bot')
|
||||||
bot.add_cog(Config(bot))
|
bot.add_cog(Config(bot))
|
||||||
33
cogs/db_api.py
Normal file
33
cogs/db_api.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import dbl
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from essentials.settings import SETTINGS
|
||||||
|
|
||||||
|
|
||||||
|
class DiscordBotsOrgAPI:
|
||||||
|
"""Handles interactions with the discordbots.org API"""
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
self.token = SETTINGS.dbl_token
|
||||||
|
self.dblpy = dbl.Client(self.bot, self.token)
|
||||||
|
self.bot.loop.create_task(self.update_stats())
|
||||||
|
|
||||||
|
async def update_stats(self):
|
||||||
|
"""This function runs every 30 minutes to automatically update your server count"""
|
||||||
|
|
||||||
|
while True:
|
||||||
|
logger.info('attempting to post server count')
|
||||||
|
try:
|
||||||
|
#await self.dblpy.post_server_count()
|
||||||
|
logger.info('posted server count ({})'.format(len(self.bot.servers)))
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception('Failed to post server count\n{}: {}'.format(type(e).__name__, e))
|
||||||
|
await asyncio.sleep(1800)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
global logger
|
||||||
|
logger = logging.getLogger('bot')
|
||||||
|
bot.add_cog(DiscordBotsOrgAPI(bot))
|
||||||
215
cogs/help.py
Normal file
215
cogs/help.py
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
import discord
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
from essentials.multi_server import get_server_pre, ask_for_server
|
||||||
|
from essentials.settings import SETTINGS
|
||||||
|
|
||||||
|
|
||||||
|
class Help:
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
self.bot = bot
|
||||||
|
self.pages = ['🏠', '🆕', '🔍', '🕹', '🛠', '💖']
|
||||||
|
|
||||||
|
async def embed_list_reaction_handler(self, page, pre, msg=None):
|
||||||
|
embed = self.get_help_embed(page, pre)
|
||||||
|
|
||||||
|
if msg is None:
|
||||||
|
msg = await self.bot.say(embed=embed)
|
||||||
|
# add reactions
|
||||||
|
for emoji in self.pages:
|
||||||
|
await self.bot.add_reaction(msg, emoji)
|
||||||
|
else:
|
||||||
|
await self.bot.edit_message(msg, embed=embed)
|
||||||
|
|
||||||
|
# wait for reactions (2 minutes)
|
||||||
|
def check(reaction, user):
|
||||||
|
return reaction.emoji if user != self.bot.user else False
|
||||||
|
|
||||||
|
res = await self.bot.wait_for_reaction(emoji=self.pages, message=msg, timeout=180, check=check)
|
||||||
|
|
||||||
|
# redirect on reaction
|
||||||
|
if res is None:
|
||||||
|
await self.bot.delete_message(msg)
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
await self.bot.remove_reaction(res.reaction.message, res.reaction.emoji, res.user)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def get_help_embed(self, page, pre):
|
||||||
|
|
||||||
|
title = f' Pollmaster Help - React with an emoji to learn more about this topic!'
|
||||||
|
embed = discord.Embed(title='', description='', colour=SETTINGS.color)
|
||||||
|
embed.set_author(name=title, icon_url=SETTINGS.title_icon)
|
||||||
|
embed.set_footer(text='Use reactions to navigate the help. This message will self-destruct in 3 minutes.')
|
||||||
|
|
||||||
|
if page == '🏠':
|
||||||
|
## POLL CREATION SHORT
|
||||||
|
embed.add_field(name='🆕 Making New Polls',
|
||||||
|
value='There are 3 ways to create a new poll.', 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?`',
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
## POLL CONTROLS
|
||||||
|
embed.add_field(name='🔍 Show Polls',
|
||||||
|
value='Commands to list and display polls.', inline=False)
|
||||||
|
embed.add_field(name='Command', value=f'`{pre}show`', inline=False)
|
||||||
|
embed.add_field(name='Arguments', value=f'Arguments: `open` (default) | `closed` | `prepared` | '
|
||||||
|
f'`<poll_label>` (optional)', inline=False)
|
||||||
|
embed.add_field(name='Examples', value=f'Examples: `{pre}show` | `{pre}show closed` | `{pre}show mascot`',
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
## POLL CONTROLS
|
||||||
|
embed.add_field(name='🕹 Poll Controls',
|
||||||
|
value='You can use these commands to interact with polls.', inline=False)
|
||||||
|
embed.add_field(name='Commands', value=f'`{pre}close` | `{pre}export` | `{pre}delete` | `{pre}activate` ',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='Arguments', value=f'Arguments: <poll_label> (required)', inline=False)
|
||||||
|
embed.add_field(name='Examples', value=f'Examples: `{pre}close mascot` | `{pre}export proposal`',
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
## POLL CONTROLS
|
||||||
|
embed.add_field(name='🛠 Configuration',
|
||||||
|
value='Various Commands to personalize Pollmaster for this server.', inline=False)
|
||||||
|
embed.add_field(name='Commands',
|
||||||
|
value=f'`{pre}userrole <role>` | `{pre}adminrole <role>` | `{pre}prefix <new_prefix>` ',
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
## ABOUT
|
||||||
|
embed.add_field(name='💖 About Pollmaster',
|
||||||
|
value='More infos about Pollmaster, the developer, where to go for further help and how you can support us.',
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
elif page == '🆕':
|
||||||
|
embed.add_field(name='🆕 Making New Polls',
|
||||||
|
value='There are three ways to create a new poll. For all three commands you can either just '
|
||||||
|
'type the command or type the command followed by the question to skip that first step.'
|
||||||
|
'Your Members need the <admin> or <user> role to use these commands. More in 🛠 Configuration.',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **Quick Poll:** `!quick <poll question>` (optional)',
|
||||||
|
value='If you just need a quick poll, this is the way to go. All you have to specify is the '
|
||||||
|
'question and your answers; the rest will be set to default values.',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **All Features:** `!new <poll question>` (optional)',
|
||||||
|
value='This command gives you full control over your poll. A step by step wizard will guide '
|
||||||
|
'you through the process and you can specify options such as Multiple Choice, '
|
||||||
|
'Anonymous Voting, Role Restriction, Role Weights and Deadline.',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **Prepare and Schedule:** `!prepare <poll question>` (optional)',
|
||||||
|
value='Similar to `!new`, this gives you all the options. But additionally, the poll will '
|
||||||
|
'be set to \'inactive\'. You can specify if the poll should activate at a certain time '
|
||||||
|
'and/or if you would like to manually `!activate` it. '
|
||||||
|
'Perfect if you are preparing for a team meeting!',
|
||||||
|
inline=False)
|
||||||
|
elif page == '🔍':
|
||||||
|
embed.add_field(name='🔍 Show Polls',
|
||||||
|
value='All users can display and list polls, with the exception of prepared polls. '
|
||||||
|
'Voting is done simply by using the reactions below the poll.',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **Show a Poll:** `!show <poll_label>`',
|
||||||
|
value='This command will refresh and display a poll. The votes in the message will always '
|
||||||
|
'be up to date and accurate. The number of reactions can be different for a number '
|
||||||
|
'of reasons and you can safely disregard them.',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **List Polls:** `!show <> | open | closed | prepared`',
|
||||||
|
value='If you just type `!show` without an argument it will default to `!show open`.'
|
||||||
|
'These commands will print a list of open, closed or prepared polls that exist on '
|
||||||
|
'the server. The first word in bold is the label of the poll and after the colon, '
|
||||||
|
'you can read the question. These lists are paginated and you can use the arrow '
|
||||||
|
'reactions to navigate larger lists.',
|
||||||
|
inline=False)
|
||||||
|
elif page == '🕹':
|
||||||
|
embed.add_field(name='🕹 Poll Controls',
|
||||||
|
value='All these commands can only be used by an <admin> or by the author of the poll. '
|
||||||
|
'Go to 🛠 Configuration for more info on the permissions.',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **Close** `!close <poll_label>`',
|
||||||
|
value='Polls will close automatically when their deadline is reached. But you can always '
|
||||||
|
'close them manually by using this command. A closed poll will lock in the votes so '
|
||||||
|
'users can no longer change, add or remove votes. Once closed, you can export a poll.',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **Delete** `!delete <poll_label>`',
|
||||||
|
value='This will *permanently and irreversibly* delete a poll from the database. '
|
||||||
|
'Once done, the label is freed up and can be assigned again.',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **Export** `!export <poll_label>`',
|
||||||
|
value='You can use this command or react with 📎 to a closed poll to generate a report. '
|
||||||
|
'The report will then be sent to you in discord via the bot. This utf8-textfile '
|
||||||
|
'(make sure to open it in an utf8-ready editor) will contain all the infos about the '
|
||||||
|
'poll, including a detailed list of participants and their votes (just a list of names '
|
||||||
|
'for anonymous polls).',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **Activate** `!activate <poll_label>`',
|
||||||
|
value='To see how you can prepare inactive polls read the `!prepare` command under Making '
|
||||||
|
'New Polls. This command is used to manually activate a prepared poll.',
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
elif page == '🛠':
|
||||||
|
embed.add_field(name='🛠 Configuration',
|
||||||
|
value='To run any of these commands you need the **\"Manage Server\"** permisson.',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **Poll Admins** `!adminrole <role name> (optional)`',
|
||||||
|
value='This gives the rights to create polls and to control ALL polls on the server. '
|
||||||
|
'To see the current role for poll admin, run the command without an argument: `!adminrole`\n'
|
||||||
|
'If you want to change the admin role to any other role, use the name of the new role '
|
||||||
|
'as the argument: !adminrole moderators',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **Poll Users** `!userrole <role name> (optional)`',
|
||||||
|
value='Everything here is identical to the admin role, except that Poll Users can only '
|
||||||
|
'control the polls which were created by themselves.',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **Change Prefix** `!prefix <new_prefix>`',
|
||||||
|
value='This will change the bot prefix for your server. If you want to use a trailing '
|
||||||
|
'whitespace, use "\w" instead of " " (discord deletes trailing whitespaces).',
|
||||||
|
inline=False)
|
||||||
|
|
||||||
|
elif page == '💖':
|
||||||
|
embed.add_field(name='💖 Pollmaster 💖',
|
||||||
|
value='If you enjoy the bot, you can show your appreciation by giving him an upvote on Discordbots.',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **Developer**',
|
||||||
|
value='Pollmaster is developed by Newti#0654',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **Support**',
|
||||||
|
value='You can support Pollmaster by sending an upvote his way or by clicking the donate link '
|
||||||
|
'on the discordbots page:\n https://discordbots.org/bot/444514223075360800',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **Support Server**',
|
||||||
|
value='If you need help with pollmaster, want to try him out or would like to give feedback '
|
||||||
|
'to the developer, feel free to join the support server: ',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='🔹 **Github**',
|
||||||
|
value='The full python source code is on my Github: https://github.com/matnad/pollmaster',
|
||||||
|
inline=False)
|
||||||
|
embed.add_field(name='**Thanks for using Pollmaster!** 💗', value='Newti', inline=False)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return embed
|
||||||
|
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
async def help(self, ctx, *, topic=None):
|
||||||
|
server = await ask_for_server(self.bot, ctx.message)
|
||||||
|
pre = await get_server_pre(self.bot, server)
|
||||||
|
res = 1
|
||||||
|
while res is not None:
|
||||||
|
if res == 1:
|
||||||
|
page = '🏠'
|
||||||
|
msg = None
|
||||||
|
else:
|
||||||
|
page = res.reaction.emoji
|
||||||
|
msg = res.reaction.message
|
||||||
|
res = await self.embed_list_reaction_handler(page, pre, msg)
|
||||||
|
# print(res.user, res.reaction, res.reaction.emoji)
|
||||||
|
# cleanup
|
||||||
|
await self.bot.delete_message(ctx.message)
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
global logger
|
||||||
|
logger = logging.getLogger('bot')
|
||||||
|
bot.add_cog(Help(bot))
|
||||||
1097
cogs/poll.py
1097
cogs/poll.py
File diff suppressed because it is too large
Load Diff
@ -1,22 +1,21 @@
|
|||||||
import copy
|
import copy
|
||||||
import pprint
|
import logging
|
||||||
import time
|
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
from settings import *
|
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from .poll import Poll
|
from .poll import Poll
|
||||||
from .utils import ask_for_server, ask_for_channel, get_server_pre
|
from utils.paginator import embed_list_paginated
|
||||||
from .utils import SETTINGS
|
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 utils.poll_name_generator import generate_word
|
||||||
|
from essentials.exceptions import StopWizard
|
||||||
|
|
||||||
|
|
||||||
class PollControls:
|
class PollControls:
|
||||||
def __init__(self, bot):
|
def __init__(self, bot):
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
|
|
||||||
## General Methods
|
# General Methods
|
||||||
async def is_admin_or_creator(self, ctx, server, owner_id, error_msg=None):
|
async def is_admin_or_creator(self, ctx, server, owner_id, error_msg=None):
|
||||||
member = server.get_member(ctx.message.author.id)
|
member = server.get_member(ctx.message.author.id)
|
||||||
if member.id == owner_id:
|
if member.id == owner_id:
|
||||||
@ -44,7 +43,47 @@ class PollControls:
|
|||||||
embed.set_footer(text=footer_text)
|
embed.set_footer(text=footer_text)
|
||||||
await self.bot.say(embed=embed)
|
await self.bot.say(embed=embed)
|
||||||
|
|
||||||
## Commands
|
# Commands
|
||||||
|
@commands.command(pass_context=True)
|
||||||
|
async def activate(self, ctx, *, short=None):
|
||||||
|
"""Activate a prepared 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.server)
|
||||||
|
error = f'Please specify the label of a poll after the close command. \n' \
|
||||||
|
f'`{pre}activate <poll_label>`'
|
||||||
|
await self.say_error(ctx, error)
|
||||||
|
else:
|
||||||
|
p = await Poll.load_from_db(self.bot, str(server.id), short)
|
||||||
|
if p is not None:
|
||||||
|
# check if already active, then just do nothing
|
||||||
|
if await p.is_active():
|
||||||
|
return
|
||||||
|
# Permission Check: Admin or Creator
|
||||||
|
if not await self.is_admin_or_creator(
|
||||||
|
ctx, server,
|
||||||
|
p.author.id,
|
||||||
|
'You don\'t have sufficient rights to activate this poll. Please talk to the server admin.'
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Activate Poll
|
||||||
|
p.active = True
|
||||||
|
if p.duration_type == 'timespan':
|
||||||
|
# add the the time between creation and activation to the duration
|
||||||
|
# -> "restart" the duration
|
||||||
|
p.duration += (p.get_activation_date() - p.time_created) / 60
|
||||||
|
await p.save_to_db()
|
||||||
|
await ctx.invoke(self.show, short)
|
||||||
|
else:
|
||||||
|
error = f'Poll with label "{short}" was not found.'
|
||||||
|
# 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(pass_context=True)
|
@commands.command(pass_context=True)
|
||||||
async def delete(self, ctx, *, short=None):
|
async def delete(self, ctx, *, short=None):
|
||||||
@ -62,9 +101,9 @@ class PollControls:
|
|||||||
if p is not None:
|
if p is not None:
|
||||||
# Permission Check: Admin or Creator
|
# Permission Check: Admin or Creator
|
||||||
if not await self.is_admin_or_creator(
|
if not await self.is_admin_or_creator(
|
||||||
ctx, server,
|
ctx, server,
|
||||||
p.author.id,
|
p.author.id,
|
||||||
'You don\'t have sufficient rights to delete this poll. Please talk to the server admin.'
|
'You don\'t have sufficient rights to delete this poll. Please talk to the server admin.'
|
||||||
):
|
):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -139,7 +178,7 @@ class PollControls:
|
|||||||
await self.say_error(ctx, error_text)
|
await self.say_error(ctx, error_text)
|
||||||
else:
|
else:
|
||||||
# sending file
|
# sending file
|
||||||
file = p.export()
|
file = await p.export()
|
||||||
if file is not None:
|
if file is not None:
|
||||||
await self.bot.send_file(
|
await self.bot.send_file(
|
||||||
ctx.message.author,
|
ctx.message.author,
|
||||||
@ -156,7 +195,6 @@ class PollControls:
|
|||||||
await self.say_error(ctx, error)
|
await self.say_error(ctx, error)
|
||||||
await ctx.invoke(self.show)
|
await ctx.invoke(self.show)
|
||||||
|
|
||||||
|
|
||||||
@commands.command(pass_context=True)
|
@commands.command(pass_context=True)
|
||||||
async def show(self, ctx, short='open', start=0):
|
async def show(self, ctx, short='open', start=0):
|
||||||
'''Show a list of open polls or show a specific poll. Parameters: "open" (default), "closed", "prepared" or <label>'''
|
'''Show a list of open polls or show a specific poll. Parameters: "open" (default), "closed", "prepared" or <label>'''
|
||||||
@ -168,11 +206,11 @@ class PollControls:
|
|||||||
if short in ['open', 'closed', 'prepared']:
|
if short in ['open', 'closed', 'prepared']:
|
||||||
query = None
|
query = None
|
||||||
if short == 'open':
|
if short == 'open':
|
||||||
query = self.bot.db.polls.find({'server_id': str(server.id), 'open': True})
|
query = self.bot.db.polls.find({'server_id': str(server.id), 'open': True, 'active': True})
|
||||||
elif short == 'closed':
|
elif short == 'closed':
|
||||||
query = self.bot.db.polls.find({'server_id': str(server.id), 'open': False})
|
query = self.bot.db.polls.find({'server_id': str(server.id), 'open': False, 'active': True})
|
||||||
elif short == 'prepared':
|
elif short == 'prepared':
|
||||||
pass #TODO: prepared showw
|
query = self.bot.db.polls.find({'server_id': str(server.id), 'active': False})
|
||||||
|
|
||||||
if query is not None:
|
if query is not None:
|
||||||
polls = [poll async for poll in query]
|
polls = [poll async for poll in query]
|
||||||
@ -186,11 +224,18 @@ class PollControls:
|
|||||||
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.title_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)
|
||||||
|
footer_text = '' # f'type {pre}show <label> to display a poll.
|
||||||
|
msg = await embed_list_paginated(self.bot, pre, polls, item_fct, embed, footer_prefix=footer_text,
|
||||||
|
per_page=8)
|
||||||
else:
|
else:
|
||||||
p = await Poll.load_from_db(self.bot, str(server.id), short)
|
p = await Poll.load_from_db(self.bot, str(server.id), short)
|
||||||
if p is not None:
|
if p is not None:
|
||||||
msg = await p.post_embed(ctx)
|
error_msg = 'This poll is inactive and you have no rights to display or view it.'
|
||||||
|
if not await p.is_active() and not await self.is_admin_or_creator(ctx, server, p.author, error_msg):
|
||||||
|
return
|
||||||
|
await p.post_embed()
|
||||||
else:
|
else:
|
||||||
error = f'Poll with label {short} was not found.'
|
error = f'Poll with label {short} was not found.'
|
||||||
pre = await get_server_pre(self.bot, server)
|
pre = await get_server_pre(self.bot, server)
|
||||||
@ -200,27 +245,30 @@ class PollControls:
|
|||||||
@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)'''
|
||||||
|
|
||||||
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, ctx.message.server.id)))
|
||||||
await poll.set_anonymous(force=False)
|
await poll.set_anonymous(force='no')
|
||||||
await poll.set_reaction(force=True)
|
await poll.set_multiple_choice(force='no')
|
||||||
await poll.set_multiple_choice(force=False)
|
|
||||||
await poll.set_options_reaction()
|
await poll.set_options_reaction()
|
||||||
await poll.set_roles(force=['@everyone'])
|
await poll.set_roles(force='all')
|
||||||
await poll.set_weights(force=[[], []])
|
await poll.set_weights(force='none')
|
||||||
await poll.set_duration(force=0.0)
|
await poll.set_duration(force='0')
|
||||||
|
|
||||||
await self.wizard(ctx, route)
|
poll = await self.wizard(ctx, route)
|
||||||
|
if poll:
|
||||||
|
await poll.post_embed()
|
||||||
|
|
||||||
@commands.command(pass_context=True)
|
@commands.command(pass_context=True)
|
||||||
async def new(self, ctx, *, cmd=None):
|
async def prepare(self, ctx, *, cmd=None):
|
||||||
'''Start the poll wizard to create a new poll step by step. Parameters: >Question> (optional) '''
|
'''Prepare a poll to use later. Parameters: <Question> (optional) '''
|
||||||
|
|
||||||
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_anonymous()
|
await poll.set_anonymous()
|
||||||
# await poll.set_reaction()
|
|
||||||
await poll.set_multiple_choice()
|
await poll.set_multiple_choice()
|
||||||
if poll.reaction:
|
if poll.reaction:
|
||||||
await poll.set_options_reaction()
|
await poll.set_options_reaction()
|
||||||
@ -230,57 +278,32 @@ class PollControls:
|
|||||||
await poll.set_weights()
|
await poll.set_weights()
|
||||||
await poll.set_duration()
|
await poll.set_duration()
|
||||||
|
|
||||||
await self.wizard(ctx, route)
|
poll = await self.wizard(ctx, route)
|
||||||
|
if poll:
|
||||||
|
await poll.post_embed(destination=ctx.message.author)
|
||||||
|
|
||||||
## Other methods
|
@commands.command(pass_context=True)
|
||||||
async def embed_list_paginated(self, ctx, items, item_fct, base_embed, msg=None, start=0, per_page=10):
|
async def new(self, ctx, *, cmd=None):
|
||||||
embed = base_embed
|
'''Start the poll wizard to create a new poll step by step. Parameters: <Question> (optional) '''
|
||||||
|
|
||||||
# generate list
|
|
||||||
embed.title = f'{items.__len__()} entries'
|
|
||||||
text = '\n'
|
|
||||||
for item in items[start:start+per_page]:
|
|
||||||
text += item_fct(item) + '\n'
|
|
||||||
embed.description = text
|
|
||||||
|
|
||||||
# footer text
|
|
||||||
pre = await get_server_pre(self.bot, ctx.message.server)
|
|
||||||
footer_text = f'Type {pre}show <label> to show a poll. '
|
|
||||||
if start > 0:
|
|
||||||
footer_text += f'React with ⏪ to show the last {per_page} entries. '
|
|
||||||
if items.__len__() > start+per_page:
|
|
||||||
footer_text += f'React with ⏩ to show the next {per_page} entries. '
|
|
||||||
if footer_text.__len__() > 0:
|
|
||||||
embed.set_footer(text=footer_text)
|
|
||||||
|
|
||||||
# post / edit message
|
|
||||||
if msg is not None:
|
|
||||||
await self.bot.edit_message(msg, embed=embed)
|
|
||||||
await self.bot.clear_reactions(msg)
|
|
||||||
else:
|
|
||||||
msg = await self.bot.say(embed=embed)
|
|
||||||
|
|
||||||
# add reactions
|
|
||||||
if start > 0:
|
|
||||||
await self.bot.add_reaction(msg, '⏪')
|
|
||||||
if items.__len__() > start+per_page:
|
|
||||||
await self.bot.add_reaction(msg, '⏩')
|
|
||||||
|
|
||||||
# wait for reactions (2 minutes)
|
|
||||||
def check(reaction, user):
|
|
||||||
return reaction.emoji if user != self.bot.user else False
|
|
||||||
res = await self.bot.wait_for_reaction(emoji=['⏪', '⏩'], message=msg, timeout=120, check=check)
|
|
||||||
|
|
||||||
# redirect on reaction
|
|
||||||
if res is None:
|
|
||||||
return
|
|
||||||
elif res.reaction.emoji == '⏪' and start > 0:
|
|
||||||
await self.embed_list_paginated(ctx, items, item_fct, base_embed, msg=msg, start=start-per_page, per_page=per_page)
|
|
||||||
elif res.reaction.emoji == '⏩' and items.__len__() > start+per_page:
|
|
||||||
await self.embed_list_paginated(ctx, items, item_fct, base_embed, msg=msg, start=start+per_page, per_page=per_page)
|
|
||||||
|
|
||||||
|
async def route(poll):
|
||||||
|
await poll.set_name(force=cmd)
|
||||||
|
await poll.set_short()
|
||||||
|
await poll.set_anonymous()
|
||||||
|
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_weights()
|
||||||
|
await poll.set_duration()
|
||||||
|
|
||||||
|
poll = await self.wizard(ctx, route)
|
||||||
|
if poll:
|
||||||
|
await poll.post_embed()
|
||||||
|
|
||||||
|
# The Wizard!
|
||||||
async def wizard(self, ctx, route):
|
async def wizard(self, ctx, route):
|
||||||
server = await ask_for_server(self.bot, ctx.message)
|
server = await ask_for_server(self.bot, ctx.message)
|
||||||
if not server:
|
if not server:
|
||||||
@ -293,7 +316,8 @@ class PollControls:
|
|||||||
# Permission Check
|
# Permission Check
|
||||||
member = server.get_member(ctx.message.author.id)
|
member = server.get_member(ctx.message.author.id)
|
||||||
result = await self.bot.db.config.find_one({'_id': str(server.id)})
|
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]:
|
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]:
|
||||||
await self.bot.send_message(ctx.message.author,
|
await self.bot.send_message(ctx.message.author,
|
||||||
'You don\'t have sufficient rights to start new polls on this server. Please talk to the server admin.')
|
'You don\'t have sufficient rights to start new polls on this server. Please talk to the server admin.')
|
||||||
return
|
return
|
||||||
@ -302,17 +326,17 @@ class PollControls:
|
|||||||
poll = Poll(self.bot, ctx, server, channel)
|
poll = Poll(self.bot, ctx, server, channel)
|
||||||
|
|
||||||
## Route to define object, passed as argument for different constructors
|
## Route to define object, passed as argument for different constructors
|
||||||
await route(poll)
|
try:
|
||||||
|
await route(poll)
|
||||||
|
poll.finalize()
|
||||||
|
except StopWizard:
|
||||||
|
return
|
||||||
|
|
||||||
## Finalize
|
# Finalize
|
||||||
if poll.stopped:
|
await poll.save_to_db()
|
||||||
print("Poll Wizard Stopped.")
|
return poll
|
||||||
else:
|
|
||||||
msg = await poll.post_embed(ctx)
|
|
||||||
await poll.save_to_db()
|
|
||||||
|
|
||||||
|
# BOT EVENTS (@bot.event)
|
||||||
## BOT EVENTS (@bot.event)
|
|
||||||
async def on_reaction_add(self, reaction, user):
|
async def on_reaction_add(self, reaction, user):
|
||||||
if user != self.bot.user:
|
if user != self.bot.user:
|
||||||
|
|
||||||
@ -340,6 +364,19 @@ class PollControls:
|
|||||||
p = await Poll.load_from_db(self.bot, server.id, short)
|
p = await Poll.load_from_db(self.bot, server.id, short)
|
||||||
if p is None:
|
if p is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# export
|
||||||
|
if (reaction.emoji == '📎'):
|
||||||
|
# sending file
|
||||||
|
file = await p.export()
|
||||||
|
if file is not None:
|
||||||
|
await self.bot.send_file(
|
||||||
|
user,
|
||||||
|
file,
|
||||||
|
content='Sending you the requested export of "{}".'.format(p.short)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
# no rights, terminate function
|
# no rights, terminate function
|
||||||
if not await p.has_required_role(user):
|
if not await p.has_required_role(user):
|
||||||
await self.bot.remove_reaction(reaction.message, reaction.emoji, user)
|
await self.bot.remove_reaction(reaction.message, reaction.emoji, user)
|
||||||
@ -362,8 +399,6 @@ class PollControls:
|
|||||||
if r != reaction:
|
if r != reaction:
|
||||||
await self.bot.remove_reaction(reaction.message, r.emoji, user)
|
await self.bot.remove_reaction(reaction.message, r.emoji, user)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def on_reaction_remove(self, reaction, user):
|
async def on_reaction_remove(self, reaction, user):
|
||||||
if reaction.emoji.startswith(('⏪', '⏩')):
|
if reaction.emoji.startswith(('⏪', '⏩')):
|
||||||
return
|
return
|
||||||
@ -393,5 +428,8 @@ class PollControls:
|
|||||||
# for anonymous polls we can't unvote because we need to hide reactions
|
# for anonymous polls we can't unvote because we need to hide reactions
|
||||||
await p.unvote(user, reaction.emoji, reaction.message)
|
await p.unvote(user, reaction.emoji, reaction.message)
|
||||||
|
|
||||||
|
|
||||||
def setup(bot):
|
def setup(bot):
|
||||||
|
global logger
|
||||||
|
logger = logging.getLogger('bot')
|
||||||
bot.add_cog(PollControls(bot))
|
bot.add_cog(PollControls(bot))
|
||||||
|
|||||||
0
essentials/__init__.py
Normal file
0
essentials/__init__.py
Normal file
47
essentials/exceptions.py
Normal file
47
essentials/exceptions.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
"""Exception Classes for the Poll Wizard"""
|
||||||
|
|
||||||
|
class StopWizard(RuntimeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InputError(RuntimeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidInput(InputError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ReservedInput(InputError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DuplicateInput(InputError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class WrongNumberOfArguments(InputError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ExpectedInteger(InputError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ExpectedSeparator(InputError):
|
||||||
|
def __init__(self, separator):
|
||||||
|
self.separator = separator
|
||||||
|
|
||||||
|
|
||||||
|
class OutOfRange(InputError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DateOutOfRange(InputError):
|
||||||
|
def __init__(self, date):
|
||||||
|
self.date = date
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidRoles(InputError):
|
||||||
|
def __init__(self, roles):
|
||||||
|
self.roles = roles
|
||||||
@ -1,11 +1,6 @@
|
|||||||
import discord
|
import discord
|
||||||
|
|
||||||
class Settings:
|
from essentials.settings import SETTINGS
|
||||||
def __init__(self):
|
|
||||||
self.color = discord.Colour(int('7289da', 16))
|
|
||||||
self.title_icon = "http://mnadler.ch/img/donat-chart-32.png"
|
|
||||||
|
|
||||||
SETTINGS = Settings()
|
|
||||||
|
|
||||||
async def get_pre(bot, message):
|
async def get_pre(bot, message):
|
||||||
'''Gets the prefix for a message.'''
|
'''Gets the prefix for a message.'''
|
||||||
@ -21,6 +16,7 @@ async def get_pre(bot, message):
|
|||||||
else:
|
else:
|
||||||
return await get_server_pre(bot, message.server)
|
return await get_server_pre(bot, message.server)
|
||||||
|
|
||||||
|
|
||||||
async def get_server_pre(bot, server):
|
async def get_server_pre(bot, server):
|
||||||
'''Gets the prefix for a server.'''
|
'''Gets the prefix for a server.'''
|
||||||
try:
|
try:
|
||||||
@ -33,13 +29,12 @@ async def get_server_pre(bot, server):
|
|||||||
|
|
||||||
|
|
||||||
async def get_servers(bot, message, short=None):
|
async def get_servers(bot, message, short=None):
|
||||||
|
'''Get best guess of relevant shared servers'''
|
||||||
if message.server is None:
|
if message.server is None:
|
||||||
|
|
||||||
list_of_shared_servers = []
|
list_of_shared_servers = []
|
||||||
for s in bot.servers:
|
for s in bot.servers:
|
||||||
if message.author.id in [m.id for m in s.members]:
|
if message.author.id in [m.id for m in s.members]:
|
||||||
list_of_shared_servers.append(s)
|
list_of_shared_servers.append(s)
|
||||||
|
|
||||||
if short is not None:
|
if short is not None:
|
||||||
query = bot.db.polls.find({'short': short})
|
query = bot.db.polls.find({'short': short})
|
||||||
if query is not None:
|
if query is not None:
|
||||||
@ -54,11 +49,10 @@ async def get_servers(bot, message, short=None):
|
|||||||
return []
|
return []
|
||||||
else:
|
else:
|
||||||
return list_of_shared_servers
|
return list_of_shared_servers
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return [message.server]
|
return [message.server]
|
||||||
|
|
||||||
|
|
||||||
async def ask_for_server(bot, message, short=None):
|
async def ask_for_server(bot, message, short=None):
|
||||||
server_list = await get_servers(bot, message, short)
|
server_list = await get_servers(bot, message, short)
|
||||||
if server_list.__len__() == 0:
|
if server_list.__len__() == 0:
|
||||||
@ -95,6 +89,7 @@ async def ask_for_server(bot, message, short=None):
|
|||||||
|
|
||||||
return server_list[nr - 1]
|
return server_list[nr - 1]
|
||||||
|
|
||||||
|
|
||||||
async def ask_for_channel(bot, server, message):
|
async def ask_for_channel(bot, server, message):
|
||||||
# if performed from a channel, return that channel
|
# if performed from a channel, return that channel
|
||||||
if str(message.channel.type) == 'text':
|
if str(message.channel.type) == 'text':
|
||||||
27
essentials/settings.py
Normal file
27
essentials/settings.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import discord
|
||||||
|
|
||||||
|
from essentials.secrets import SECRETS
|
||||||
|
|
||||||
|
|
||||||
|
class Settings:
|
||||||
|
def __init__(self):
|
||||||
|
self.color = discord.Colour(int('7289da', 16))
|
||||||
|
self.title_icon = "http://mnadler.ch/img/donat-chart-32.png"
|
||||||
|
self.author_icon = "http://mnadler.ch/img/donat-chart-32.png"
|
||||||
|
self.report_icon = "http://mnadler.ch/img/poll-topic-64.png"
|
||||||
|
self.owner_id = 117687652278468610
|
||||||
|
self.msg_errors = False
|
||||||
|
self.log_errors = True
|
||||||
|
self.invite_link = \
|
||||||
|
'https://discordapp.com/api/oauth2/authorize?client_id=444831720659877889&permissions=126016&scope=bot'
|
||||||
|
|
||||||
|
self.load_secrets()
|
||||||
|
|
||||||
|
def load_secrets(self):
|
||||||
|
# secret
|
||||||
|
self.dbl_token = SECRETS.dbl_token
|
||||||
|
self.mongo_db = SECRETS.mongo_db
|
||||||
|
self.bot_token = SECRETS.bot_token
|
||||||
|
|
||||||
|
|
||||||
|
SETTINGS = Settings()
|
||||||
100
pollmaster.py
100
pollmaster.py
@ -1,43 +1,99 @@
|
|||||||
|
import datetime
|
||||||
import os
|
import os
|
||||||
|
import traceback
|
||||||
|
import logging
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
import discord
|
||||||
|
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
from motor.motor_asyncio import AsyncIOMotorClient
|
from motor.motor_asyncio import AsyncIOMotorClient
|
||||||
|
|
||||||
#os.environ['dbltoken'] = 'ABC' #for website..
|
from essentials.multi_server import get_pre
|
||||||
from cogs.utils import get_pre
|
from essentials.settings import SETTINGS
|
||||||
|
|
||||||
os.environ['mongoDB'] = 'mongodb://localhost:27017/pollmaster'
|
|
||||||
|
|
||||||
# async def get_pre(bot, message):
|
bot_config = {
|
||||||
# '''Gets the prefix for the server.'''
|
'command_prefix': get_pre,
|
||||||
# print(str(message.content))
|
'pm_help': False,
|
||||||
# try:
|
'status': discord.Status.online,
|
||||||
# result = await bot.db.config.find_one({'_id': str(message.server.id)})
|
'owner_id': SETTINGS.owner_id,
|
||||||
# except AttributeError:
|
'fetch_offline_members': False
|
||||||
# return '!'
|
}
|
||||||
# if not result or not result.get('prefix'):
|
|
||||||
# return '!'
|
|
||||||
# return result.get('prefix')
|
|
||||||
|
|
||||||
bot = commands.Bot(command_prefix=get_pre)
|
bot = commands.Bot(**bot_config)
|
||||||
dbltoken = os.environ.get('dbltoken')
|
bot.remove_command('help')
|
||||||
|
|
||||||
extensions = ['cogs.config','cogs.poll_controls']
|
# logger
|
||||||
|
# create logger with 'spam_application'
|
||||||
|
logger = logging.getLogger('bot')
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
# create file handler which logs even debug messages
|
||||||
|
fh = logging.FileHandler('pollmaster.log')
|
||||||
|
fh.setLevel(logging.DEBUG)
|
||||||
|
# create console handler with a higher log level
|
||||||
|
ch = logging.StreamHandler()
|
||||||
|
ch.setLevel(logging.ERROR)
|
||||||
|
# create formatter and add it to the handlers
|
||||||
|
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||||
|
fh.setFormatter(formatter)
|
||||||
|
ch.setFormatter(formatter)
|
||||||
|
# add the handlers to the logger
|
||||||
|
logger.addHandler(fh)
|
||||||
|
logger.addHandler(ch)
|
||||||
|
|
||||||
|
extensions = ['cogs.config','cogs.poll_controls', 'cogs.help', 'cogs.db_api']
|
||||||
for ext in extensions:
|
for ext in extensions:
|
||||||
bot.load_extension(ext)
|
bot.load_extension(ext)
|
||||||
|
|
||||||
@bot.event
|
@bot.event
|
||||||
async def on_ready():
|
async def on_ready():
|
||||||
|
bot.owner = await bot.get_user_info(str(SETTINGS.owner_id))
|
||||||
|
|
||||||
mongo = AsyncIOMotorClient(os.environ.get('mongodb'))
|
mongo = AsyncIOMotorClient(SETTINGS.mongo_db)
|
||||||
bot.db = mongo.pollmaster
|
bot.db = mongo.pollmaster
|
||||||
bot.session = aiohttp.ClientSession()
|
bot.session = aiohttp.ClientSession()
|
||||||
print(bot.db)
|
print(bot.db)
|
||||||
# document = {'key': 'value'}
|
await bot.change_presence(game=discord.Game(name=f'pm!help'))
|
||||||
# result = await bot.db.test_collection.insert_one(document)
|
|
||||||
# print('result %s' % repr(result.inserted_id))
|
|
||||||
|
|
||||||
|
|
||||||
bot.run('NDQ0ODMxNzIwNjU5ODc3ODg5.DdhqZw.fsicJ8FffOYn670uPGuC4giXIlk')
|
@bot.event
|
||||||
|
async def on_command_error(e, ctx):
|
||||||
|
if SETTINGS.log_errors:
|
||||||
|
ignored_exceptions = (
|
||||||
|
commands.MissingRequiredArgument,
|
||||||
|
commands.CommandNotFound,
|
||||||
|
commands.DisabledCommand,
|
||||||
|
commands.BadArgument,
|
||||||
|
commands.NoPrivateMessage,
|
||||||
|
commands.CheckFailure,
|
||||||
|
commands.CommandOnCooldown,
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(e, ignored_exceptions):
|
||||||
|
# log warnings
|
||||||
|
logger.warning(f'{type(e).__name__}: {e}\n{"".join(traceback.format_tb(e.__traceback__))}')
|
||||||
|
return
|
||||||
|
|
||||||
|
# log error
|
||||||
|
logger.error(f'{type(e).__name__}: {e}\n{"".join(traceback.format_tb(e.__traceback__))}')
|
||||||
|
|
||||||
|
if SETTINGS.msg_errors:
|
||||||
|
# send discord message for unexpected errors
|
||||||
|
e = discord.Embed(
|
||||||
|
title=f"Error With command: {ctx.command.name}",
|
||||||
|
description=f"```py\n{type(e).__name__}: {e}\n```\n\nContent:{ctx.message.content}"
|
||||||
|
f"\n\tServer: {ctx.message.server}\n\tChannel: <#{ctx.message.channel.id}>"
|
||||||
|
f"\n\tAuthor: <@{ctx.message.author.id}>",
|
||||||
|
timestamp=ctx.message.timestamp
|
||||||
|
)
|
||||||
|
await bot.send_message(bot.owner,embed=e)
|
||||||
|
|
||||||
|
@bot.event
|
||||||
|
async def on_server_join(server):
|
||||||
|
result = await bot.db.config.find_one({'_id': str(server.id)})
|
||||||
|
if result is None:
|
||||||
|
await bot.db.config.update_one({'_id': str(server.id)},
|
||||||
|
{'$set': {'prefix': 'pm!', 'admin_role': 'polladmin', 'user_role': 'polluser'}},
|
||||||
|
upsert=True)
|
||||||
|
|
||||||
|
bot.run(SETTINGS.bot_token)
|
||||||
@ -1,4 +0,0 @@
|
|||||||
import discord
|
|
||||||
|
|
||||||
|
|
||||||
PURPLE = discord.Colour(int('7289da', 16))
|
|
||||||
44
utils/paginator.py
Normal file
44
utils/paginator.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
async def embed_list_paginated(bot, pre, items, item_fct, base_embed, footer_prefix='', msg=None, start=0, per_page=10):
|
||||||
|
embed = base_embed
|
||||||
|
|
||||||
|
# generate list
|
||||||
|
embed.title = f'{items.__len__()} entries'
|
||||||
|
text = '\n'
|
||||||
|
for item in items[start:start+per_page]:
|
||||||
|
text += item_fct(item) + '\n'
|
||||||
|
embed.description = text
|
||||||
|
|
||||||
|
# footer text
|
||||||
|
#footer_text = f'Type {pre}show <label> to show a poll. '
|
||||||
|
if start > 0:
|
||||||
|
footer_prefix += f'React with ⏪ to show the last {per_page} entries. '
|
||||||
|
if items.__len__() > start+per_page:
|
||||||
|
footer_prefix += f'React with ⏩ to show the next {per_page} entries. '
|
||||||
|
if footer_prefix.__len__() > 0:
|
||||||
|
embed.set_footer(text=footer_prefix)
|
||||||
|
|
||||||
|
# post / edit message
|
||||||
|
if msg is not None:
|
||||||
|
await bot.edit_message(msg, embed=embed)
|
||||||
|
await bot.clear_reactions(msg)
|
||||||
|
else:
|
||||||
|
msg = await bot.say(embed=embed)
|
||||||
|
|
||||||
|
# add reactions
|
||||||
|
if start > 0:
|
||||||
|
await bot.add_reaction(msg, '⏪')
|
||||||
|
if items.__len__() > start+per_page:
|
||||||
|
await bot.add_reaction(msg, '⏩')
|
||||||
|
|
||||||
|
# wait for reactions (2 minutes)
|
||||||
|
def check(reaction, user):
|
||||||
|
return reaction.emoji if user != bot.user else False
|
||||||
|
res = await bot.wait_for_reaction(emoji=['⏪', '⏩'], message=msg, timeout=120, check=check)
|
||||||
|
|
||||||
|
# redirect on reaction
|
||||||
|
if res is None:
|
||||||
|
return
|
||||||
|
elif res.reaction.emoji == '⏪' and start > 0:
|
||||||
|
await embed_list_paginated(bot, pre, items, item_fct, base_embed, msg=msg, start=start-per_page, per_page=per_page)
|
||||||
|
elif res.reaction.emoji == '⏩' and items.__len__() > start+per_page:
|
||||||
|
await embed_list_paginated(bot, pre, items, item_fct, base_embed, msg=msg, start=start+per_page, per_page=per_page)
|
||||||
Loading…
Reference in New Issue
Block a user