countdown-bot

A Discord bot that runs countdown games and generates analytics
git clone https://git.ashermorgan.net/countdown-bot/
Log | Files | Refs | README

coreCog.py (8559B)


      1 # Import dependencies
      2 import discord
      3 from discord.ext import commands
      4 from datetime import timedelta
      5 
      6 # Import modules
      7 from .botUtilities import COLORS, CommandError, CountdownNotFound, isCountdown, loadCountdown, getContextCountdown, addMessage
      8 
      9 
     10 
     11 class Core(commands.Cog):
     12     def __init__(self, bot, db_connection):
     13         self.bot = bot
     14         self.db_connection = db_connection
     15 
     16 
     17 
     18     @commands.Cog.listener()
     19     async def on_message(self, obj):
     20         # Parse countdown message
     21         with self.db_connection.cursor() as cur:
     22             if (await addMessage(cur, obj)):
     23                 self.db_connection.commit()
     24 
     25 
     26 
     27     @commands.command()
     28     async def activate(self, ctx):
     29         """
     30         Turns a channel into a countdown
     31         """
     32 
     33         with self.db_connection.cursor() as cur:
     34             # Check if channel is already a countdown
     35             if (isCountdown(cur, ctx.channel.id)):
     36                 raise CommandError("This channel is already a countdown")
     37 
     38             # Check if channel is a DM
     39             if (not isinstance(ctx.channel, discord.channel.TextChannel)):
     40                 raise CommandError("This command must be run inside a server")
     41 
     42             # Check if user isn't authorized
     43             if (not ctx.message.author.guild_permissions.administrator):
     44                 raise CommandError("You must be an administrator to turn a channel into a countdown")
     45 
     46             # Create countdown
     47             cur.execute("CALL createCountdown(%s, %s, %s);",
     48                 (ctx.channel.id, ctx.channel.guild.id, self.bot.prefix))
     49 
     50             # Send initial response
     51             self.bot.logger.info(f"Activated {self.bot.get_channel(ctx.channel.id)} (ID {ctx.channel.id}) as a countdown")
     52             embed = discord.Embed(title=":clock3: Loading Countdown", description="This channel is now a countdown\nPlease wait to start counting", color=COLORS["embed"])
     53             msg = await ctx.send(embed=embed)
     54 
     55             # Load countdown
     56             await loadCountdown(self.bot, ctx.channel.id)
     57             self.db_connection.commit()
     58 
     59             # Send final response
     60             embed = discord.Embed(title=":white_check_mark: Countdown Activated", description="This channel is now a countdown\nYou may start counting!", color=COLORS["embed"])
     61             await msg.edit(embed=embed)
     62 
     63 
     64 
     65     @commands.command()
     66     async def config(self, ctx, key=None, *args):
     67         """
     68         Shows and modifies countdown settings
     69         """
     70 
     71         # Create embed
     72         embed = discord.Embed(title=":gear: Countdown Settings", color=COLORS["embed"])
     73 
     74         # Make sure context is in a server
     75         if (not isinstance(ctx.channel, discord.channel.TextChannel)):
     76             raise CommandError("This command must be run in a countdown channel or a server with a countdown channel")
     77 
     78         with self.db_connection.cursor() as cur:
     79             # Get countdown channel
     80             countdown = getContextCountdown(cur, ctx)
     81 
     82             if not countdown:
     83                 raise CountdownNotFound()
     84 
     85             # Get / set settings
     86             if (key is None):
     87                 embed.description = f"**Countdown Channel:** <#{countdown}>\n"
     88 
     89                 cur.execute("SELECT * from getPrefixes(%s);", (countdown,))
     90                 prefixes = [x["prefix"] for x in cur.fetchall()]
     91                 embed.description += f"**Command Prefixes:** `{'`, `'.join(prefixes)}`\n"
     92 
     93                 cur.execute("CALL getTimezone(%s, null);", (countdown,))
     94                 timezone = cur.fetchone()["_timezone"]
     95                 if (timezone >= 0):
     96                     embed.description += f"**Countdown Timezone:** UTC+{timezone:.2f}\n"
     97                 else:
     98                     embed.description += f"**Countdown Timezone:** UTC-{abs(timezone):.2f}\n"
     99 
    100                 cur.execute("SELECT * FROM getReactions(%s, NULL);", (countdown,))
    101                 reactions = cur.fetchall()
    102                 if (len(reactions) == 0):
    103                     embed.description += f"**Reactions:** none\n"
    104                 else:
    105                     embed.description += f"**Reactions:**\n"
    106                 for number in reversed(list(set([x["number"] for x in reactions]))):
    107                     embed.description += f"**-** #{number}: {', '.join([x["value"] for x in reactions if x["number"] == number])}\n"
    108 
    109                 embed.description += f"\nUse `{ctx.prefix}help config` to view more information about settings\n"
    110                 embed.description += f"Use `{ctx.prefix}config <key> <value>` to modify settings\n"
    111             elif (not ctx.message.author.guild_permissions.administrator):
    112                 raise CommandError("You must be an administrator to modify settings")
    113             elif (len(args) == 0):
    114                 raise CommandError("Please provide a value for the setting")
    115             elif (key in ["tz", "timezone"]):
    116                 try:
    117                     timezone = float(args[0])
    118                 except:
    119                     raise CommandError(f"Invalid timezone: `{args[0]}`")
    120                 else:
    121                     cur.execute("CALL setTimezone(%s, %s);", (countdown, timezone))
    122                     if (timezone >= 0):
    123                         embed.description = f"Timezone set to UTC+{timezone:.2f}\n"
    124                     else:
    125                         embed.description = f"Timezone set to UTC-{abs(timezone):.2f}\n"
    126             elif (key in ["prefix", "prefixes"]):
    127                 cur.execute("CALL setPrefixes(%s, %s);", (countdown, list(args)))
    128                 embed.description = f"Prefixes updated"
    129             elif (key in ["react"]):
    130                 try:
    131                     number = int(args[0])
    132                 except:
    133                     raise CommandError(f"Invalid number: `{args[0]}`")
    134                 if (number < 0):
    135                     raise CommandError("Number must be greater than zero")
    136                 cur.execute("CALL setReactions(%s, %s, %s);",
    137                     (countdown, number, list(args[1:])))
    138                 if (len(args) == 1):
    139                     embed.description = f"Removed reactions for #{number}"
    140                 else:
    141                     embed.description = f"Updated reactions for #{number}"
    142             else:
    143                 raise CommandError(f"Setting not found: `{key}`")
    144 
    145             # Save changes
    146             self.db_connection.commit()
    147 
    148         # Send embed
    149         await ctx.send(embed=embed)
    150 
    151 
    152 
    153     @commands.command()
    154     async def deactivate(self, ctx):
    155         """
    156         Deactivates a countdown channel
    157         """
    158 
    159         with self.db_connection.cursor() as cur:
    160             # Check if channel isn't a countdown
    161             if (not isCountdown(cur, ctx.channel.id)):
    162                 raise CommandError("This channel isn't a countdown")
    163 
    164             # Check if user isn't authorized
    165             if (not ctx.author.guild_permissions.administrator):
    166                 raise CommandError("You must be an administrator to deactivate a countdown channel")
    167 
    168             # Delete countdown
    169             cur.execute("CALL deleteCountdown(%s);",
    170                 (ctx.channel.id,))
    171             self.db_connection.commit()
    172 
    173             # Send response
    174             self.bot.logger.info(f"Deactivated {self.bot.get_channel(ctx.channel.id)} (ID {ctx.channel.id}) as a countdown")
    175             embed = discord.Embed(title=":octagonal_sign: Countdown Deactivated", description="This channel is no longer a countdown", color=COLORS["embed"])
    176             await ctx.send(embed=embed)
    177 
    178 
    179 
    180     @commands.command()
    181     async def reload(self, ctx):
    182         """
    183         Reloads the countdown cache
    184         """
    185 
    186         with self.db_connection.cursor() as cur:
    187             # Check if channel isn't a countdown
    188             if (not isCountdown(cur, ctx.channel.id)):
    189                 raise CommandError("Countdown not found\nThis command must be used in a countdown channel")
    190 
    191             # Send initial response
    192             embed = discord.Embed(title=":clock3: Reloading Countdown Cache", description="Please wait to continue counting", color=COLORS["embed"])
    193             msg = await ctx.channel.send(embed=embed)
    194 
    195             # Reload messages
    196             await loadCountdown(self.bot, ctx.channel.id)
    197             self.db_connection.commit()
    198 
    199             # Send final response
    200             self.bot.logger.info(f"Reloaded messages from {self.bot.get_channel(ctx.channel.id)} (ID {ctx.channel.id})")
    201             embed = discord.Embed(title=":white_check_mark: Countdown Cache Reloaded", description="Done! You may continue counting!", color=COLORS["embed"])
    202             await msg.edit(embed=embed)