import argparse import os import asyncio import datetime import logging import re import shlex import discord import pytz import time from discord.ext import commands from utils.misc import CustomFormatter from models.poll import Poll from utils.paginator import embed_list_paginated from essentials.multi_server import get_server_pre, ask_for_server, ask_for_channel from essentials.settings import SETTINGS from utils.poll_name_generator import generate_word from essentials.exceptions import StopWizard # A-Z Emojis for Discord AZ_EMOJIS = [(b'\\U0001f1a'.replace(b'a', bytes(hex(224 + (6 + i))[2:], "utf-8"))).decode("unicode-escape") for i in range(26)] class PollControls(commands.Cog): def __init__(self, bot): self.bot = bot self.bot.loop.create_task(self.close_polls()) self.ignore_next_removed_reaction = {} # # General Methods def get_label(self, message: discord.Message): label = None if message and message.embeds: embed = message.embeds[0] label_object = embed.author if label_object: label_full = label_object.name if label_full and label_full.startswith('>> '): label = label_full[3:] return label async def close_polls(self): """This function runs every 60 seconds to schedule prepared polls and close expired polls""" while True: try: if not hasattr(self.bot, 'db'): """await asyncio.sleep(30)""" logger.info("DB not available yet") time.sleep(30) continue query = self.bot.db.polls.find({'active': False, 'activation': {"$not": re.compile("0")}}) if query: for pd in [poll async for poll in query]: p = Poll(self.bot, load=True) await p.from_dict(pd) if not p.server: continue if p.active: try: await p.channel.send('This poll has been scheduled and is active now!') await p.post_embed(p.channel) except: continue query = self.bot.db.polls.find({'open': True, 'duration': {"$not": re.compile("0")}}) if query: for pd in [poll async for poll in query]: p = Poll(self.bot, load=True) await p.from_dict(pd) if not p.server: continue if not p.open: try: await p.channel.send('This poll has reached the deadline and is closed!') await p.post_embed(p.channel) except: continue except AttributeError as ae: # Database not loaded yet logger.warning("Attribute Error in close_polls loop") logger.exception(ae) pass except Exception as ex: # Never break this loop due to an error logger.error("Other Error in close_polls loop") logger.exception(ex) pass await asyncio.sleep(60) def get_lock(self, server_id): if not self.bot.locks.get(server_id): self.bot.locks[server_id] = asyncio.Lock() return self.bot.locks.get(server_id) async def is_admin_or_creator(self, ctx, server, owner_id, error_msg=None): member = server.get_member(ctx.message.author.id) if member.id == owner_id: return True elif member.guild_permissions.manage_guild: return 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]: return True else: if error_msg is not None: await ctx.send(ctx.message.author, error_msg) return False async def say_error(self, ctx, error_text, footer_text=None): embed = discord.Embed(title='', description=error_text, colour=SETTINGS.color) embed.set_author(name='Error', icon_url=SETTINGS.author_icon) if footer_text is not None: embed.set_footer(text=footer_text) await ctx.send(embed=embed) async def say_embed(self, ctx, say_text='', title='Pollmaster', footer_text=None): embed = discord.Embed(title='', description=say_text, colour=SETTINGS.color) embed.set_author(name=title, icon_url=SETTINGS.author_icon) if footer_text is not None: embed.set_footer(text=footer_text) await ctx.send(embed=embed) # Commands @commands.command() async def activate(self, ctx, *, short=None): """Activate a prepared poll. Parameter: