commit 09db08c9e679a3eab3da08904003182a83674a32
parent 41a95fedaf35ec07dd5a7263750837937b574642
Author: ashermorgan <59518073+ashermorgan@users.noreply.github.com>
Date: Sat, 3 Jul 2021 14:26:00 -0700
Improve error handling
Diffstat:
5 files changed, 242 insertions(+), 268 deletions(-)
diff --git a/src/analyticsCog.py b/src/analyticsCog.py
@@ -10,7 +10,7 @@ import re
import tempfile
# Import modules
-from src.botUtilities import COLORS, getContextCountdown, getUsername, getContributor, ContributorNotFound
+from src.botUtilities import COLORS, getContextCountdown, getUsername, getContributor, CommandError
from src.models import POINT_RULES
@@ -28,25 +28,14 @@ class Analytics(commands.Cog):
Shows all countdown analytics
"""
- with self.databaseSessionMaker() as session:
- # Get countdown channel
- countdown = getContextCountdown(session, ctx)
-
- # Check if countdown is empty
- if (len(countdown.messages) == 0):
- embed=discord.Embed(title=":bar_chart: Countdown Analytics", color=COLORS["error"])
- embed.description = "The countdown is empty"
- await ctx.send(embed=embed)
-
- # Run analytics commands
- else:
- await self.contributors(ctx, "")
- await self.contributors(ctx, "history")
- if (len(countdown.messages) >= 2): await self.eta(ctx) # Countdown must have 2 messages to run eta command
- await self.heatmap(ctx)
- await self.leaderboard(ctx)
- await self.progress(ctx)
- await self.speed(ctx)
+ # Run analytics commands
+ await self.contributors(ctx, "")
+ await self.contributors(ctx, "history")
+ await self.eta(ctx)
+ await self.heatmap(ctx)
+ await self.leaderboard(ctx)
+ await self.progress(ctx)
+ await self.speed(ctx)
@@ -72,10 +61,7 @@ class Analytics(commands.Cog):
embed=discord.Embed(title=":busts_in_silhouette: Countdown Contributors", color=COLORS["embed"])
# Make sure the countdown has started
- if (len(countdown.messages) == 0):
- embed.color = COLORS["error"]
- embed.description = "The countdown is empty."
- elif (option.lower() in ["h", "history"]):
+ if (option.lower() in ["h", "history"]):
# Create figure
fig, ax = plt.subplots()
ax.set_xlabel("Progress")
@@ -138,9 +124,7 @@ class Analytics(commands.Cog):
embed.add_field(name="Contributions",value=contributions, inline=True)
embed.set_image(url="attachment://image.png")
else:
- embed.color = COLORS["error"]
- embed.description = f"Unrecognized option: `{option}`\n"
- embed.description += f"Use `{(await self.bot.get_prefix(ctx))[0]}help contributors` to view help information"
+ raise CommandError(f"Unrecognized option: `{option}`")
# Send embed
try:
@@ -176,55 +160,51 @@ class Analytics(commands.Cog):
# Parse period
try:
period = float(period)
- except:
- embed.color = COLORS["error"]
- embed.description = "The period must be a number"
+ except ValueError:
+ raise CommandError(f"Invalid number: `{period}`")
+
+ # Make sure period is valid
+ if (period < 0.01):
+ raise CommandError("The period cannot be less than 0.01 hours")
+
+ # Get stats
+ eta = countdown.eta(timedelta(hours=period))
+
+ # Create figure
+ fig, ax = plt.subplots()
+ ax.set_xlabel("Time")
+ fig.autofmt_xdate()
+
+ # Add ETA data to graph
+ ax.plot(eta[0], eta[1], "C0", label="Estimated Completion Date")
+
+ # Add reference line graph
+ ax.plot([eta[0][0], eta[0][-1]], [eta[0][0], eta[0][-1]], "--C1", label="Current Date")
+
+ # Add legend
+ ax.legend()
+
+ # Save graph
+ fig.savefig(tmp.name, bbox_inches="tight", pad_inches=0.2)
+ file = discord.File(tmp.name, filename="image.png")
+
+ # Calculate embed data
+ maxEta = max(eta[1])
+ maxDate = eta[0][eta[1].index(maxEta)]
+ minEta = min(eta[1][1:])
+ minDate = eta[0][eta[1].index(minEta)]
+ end = eta[1][-1] + timedelta(hours=countdown.timezone)
+ endDiff = eta[1][-1] - datetime.utcnow()
+
+ # Add content to embed
+ embed.description = f"**Countdown Channel:** <#{countdown.id}>\n\n"
+ embed.description += f"**Maximum Estimate:** {maxEta.date()} (on {maxDate.date()})\n"
+ embed.description += f"**Minimum Estimate:** {minEta.date()} (on {minDate.date()})\n"
+ if endDiff < timedelta(seconds=0):
+ embed.description += f"**Actual Completion Date:** {end.date()} ({(-1 * endDiff).days:,} days ago)\n"
else:
- if (len(countdown.messages) < 2):
- embed.color = COLORS["embed"]
- embed.description = "The countdown must have at least two messages"
- elif (period < 0.01):
- embed.color = COLORS["error"]
- embed.description = "The period cannot be less than 0.01 hours"
- else:
- # Get stats
- eta = countdown.eta(timedelta(hours=period))
-
- # Create figure
- fig, ax = plt.subplots()
- ax.set_xlabel("Time")
- fig.autofmt_xdate()
-
- # Add ETA data to graph
- ax.plot(eta[0], eta[1], "C0", label="Estimated Completion Date")
-
- # Add reference line graph
- ax.plot([eta[0][0], eta[0][-1]], [eta[0][0], eta[0][-1]], "--C1", label="Current Date")
-
- # Add legend
- ax.legend()
-
- # Save graph
- fig.savefig(tmp.name, bbox_inches="tight", pad_inches=0.2)
- file = discord.File(tmp.name, filename="image.png")
-
- # Calculate embed data
- maxEta = max(eta[1])
- maxDate = eta[0][eta[1].index(maxEta)]
- minEta = min(eta[1][1:])
- minDate = eta[0][eta[1].index(minEta)]
- end = eta[1][-1] + timedelta(hours=countdown.timezone)
- endDiff = eta[1][-1] - datetime.utcnow()
-
- # Add content to embed
- embed.description = f"**Countdown Channel:** <#{countdown.id}>\n\n"
- embed.description += f"**Maximum Estimate:** {maxEta.date()} (on {maxDate.date()})\n"
- embed.description += f"**Minimum Estimate:** {minEta.date()} (on {minDate.date()})\n"
- if endDiff < timedelta(seconds=0):
- embed.description += f"**Actual Completion Date:** {end.date()} ({(-1 * endDiff).days:,} days ago)\n"
- else:
- embed.description += f"**Current Estimate:** {end.date()} ({endDiff.days:,} days from now)\n"
- embed.set_image(url="attachment://image.png")
+ embed.description += f"**Current Estimate:** {end.date()} ({endDiff.days:,} days from now)\n"
+ embed.set_image(url="attachment://image.png")
# Send embed
try:
@@ -258,14 +238,10 @@ class Analytics(commands.Cog):
embed=discord.Embed(title=":calendar_spiral: Countdown Heatmap", color=COLORS["embed"])
# Get user
- try:
- if (user == None): userID = None
- else: userID = await getContributor(self.bot, countdown, user)
- except ContributorNotFound:
- embed.color = COLORS["error"]
- embed.description = f"Contributor not found: `{user}`"
- await ctx.send(embed=embed)
- return
+ if (user == None):
+ userID = None
+ else:
+ userID = await getContributor(self.bot, countdown, user)
# Get heatmap matrix
heatmapMatrix = np.ma.masked_equal(np.array(countdown.heatmap(userID)), 0)
@@ -326,10 +302,7 @@ class Analytics(commands.Cog):
embed=discord.Embed(title=":trophy: Countdown Leaderboard", color=COLORS["embed"])
# Make sure the countdown has started
- if (len(countdown.messages) == 0):
- embed.color = COLORS["error"]
- embed.description = "The countdown is empty."
- elif (user is None):
+ if (user is None):
# Add description
embed.description = f"**Countdown Channel:** <#{countdown.id}>"
@@ -355,16 +328,11 @@ class Analytics(commands.Cog):
embed.add_field(name="Numbers", value=rules, inline=True)
embed.add_field(name="Points", value=values, inline=True)
else:
- try:
- if (re.match("^\d+$", user) and int(user) > 0 and int(user) <= len(leaderboard)):
- rank = int(user) - 1
- else:
- rank = [x["author"] for x in leaderboard].index(await getContributor(self.bot, countdown, user))
- except ContributorNotFound:
- embed.color = COLORS["error"]
- embed.description = f"Contributor not found: `{user}`"
- await ctx.send(embed=embed)
- return
+ # Get user rank
+ if (re.match("^\d+$", user) and int(user) > 0 and int(user) <= len(leaderboard)):
+ rank = int(user) - 1
+ else:
+ rank = [x["author"] for x in leaderboard].index(await getContributor(self.bot, countdown, user))
# Add description
embed.description = f"**Countdown Channel:** <#{countdown.id}>\n\n"
@@ -410,45 +378,40 @@ class Analytics(commands.Cog):
# Create embed
embed=discord.Embed(title=":chart_with_downwards_trend: Countdown Progress", color=COLORS["embed"])
- # Make sure the countdown has started
- if (len(countdown.messages) == 0):
- embed.color = COLORS["error"]
- embed.description = "The countdown is empty."
- else:
- # Get progress stats
- stats = countdown.progress()
+ # Get progress stats
+ stats = countdown.progress()
- # Create figure
- fig, ax = plt.subplots()
- ax.set_xlabel("Time")
- ax.set_ylabel("Progress")
- fig.autofmt_xdate()
+ # Create figure
+ fig, ax = plt.subplots()
+ ax.set_xlabel("Time")
+ ax.set_ylabel("Progress")
+ fig.autofmt_xdate()
- # Add data to graph
- x = [stats["start"] + timedelta(hours=countdown.timezone)] + [x["time"] + timedelta(hours=countdown.timezone) for x in stats["progress"]]
- y = [0] + [x["progress"] for x in stats["progress"]]
- ax.plot(x, y)
+ # Add data to graph
+ x = [stats["start"] + timedelta(hours=countdown.timezone)] + [x["time"] + timedelta(hours=countdown.timezone) for x in stats["progress"]]
+ y = [0] + [x["progress"] for x in stats["progress"]]
+ ax.plot(x, y)
- # Save graph
- fig.savefig(tmp.name, bbox_inches="tight", pad_inches=0.2)
- file = discord.File(tmp.name, filename="image.png")
+ # Save graph
+ fig.savefig(tmp.name, bbox_inches="tight", pad_inches=0.2)
+ file = discord.File(tmp.name, filename="image.png")
- # Calculate embed data
- start = (stats["start"] + timedelta(hours=countdown.timezone)).date()
- startDiff = (datetime.utcnow() - stats["start"]).days
- end = (stats["eta"] + timedelta(hours=countdown.timezone)).date()
- endDiff = stats["eta"] - datetime.utcnow()
+ # Calculate embed data
+ start = (stats["start"] + timedelta(hours=countdown.timezone)).date()
+ startDiff = (datetime.utcnow() - stats["start"]).days
+ end = (stats["eta"] + timedelta(hours=countdown.timezone)).date()
+ endDiff = stats["eta"] - datetime.utcnow()
- # Add content to embed
- embed.description = f"**Countdown Channel:** <#{countdown.id}>\n\n"
- embed.description += f"**Progress:** {stats['total'] - stats['current']:,} / {stats['total']:,} ({round(stats['percentage'], 1)}%)\n"
- embed.description += f"**Average Progress per Day:** {round(stats['rate']):,}\n"
- embed.description += f"**Start Date:** {start} ({startDiff:,} days ago)\n"
- if endDiff < timedelta(seconds=0):
- embed.description += f"**End Date:** {end} ({(-1 * endDiff).days:,} days ago)\n"
- else:
- embed.description += f"**Estimated End Date:** {end} ({endDiff.days:,} days from now)\n"
- embed.set_image(url="attachment://image.png")
+ # Add content to embed
+ embed.description = f"**Countdown Channel:** <#{countdown.id}>\n\n"
+ embed.description += f"**Progress:** {stats['total'] - stats['current']:,} / {stats['total']:,} ({round(stats['percentage'], 1)}%)\n"
+ embed.description += f"**Average Progress per Day:** {round(stats['rate']):,}\n"
+ embed.description += f"**Start Date:** {start} ({startDiff:,} days ago)\n"
+ if endDiff < timedelta(seconds=0):
+ embed.description += f"**End Date:** {end} ({(-1 * endDiff).days:,} days ago)\n"
+ else:
+ embed.description += f"**Estimated End Date:** {end} ({endDiff.days:,} days from now)\n"
+ embed.set_image(url="attachment://image.png")
# Send embed
try:
@@ -484,48 +447,44 @@ class Analytics(commands.Cog):
# Parse period
try:
period = float(period)
- except:
- embed.color = COLORS["error"]
- embed.description = "The period must be a number"
+ except ValueError:
+ raise CommandError(f"Invalid number: `{period}`")
+
+ # Make sure period is valid
+ if (period < 0.01):
+ raise CommandError("The period cannot be less than 0.01 hours")
+
+ # Get stats
+ stats = countdown.progress()
+ period = timedelta(hours=period)
+ speed = countdown.speed(period)
+
+ # Create figure
+ fig, ax = plt.subplots()
+ ax.set_xlabel("Time")
+ ax.set_ylabel("Progress per Period")
+ fig.autofmt_xdate()
+
+ # Add data to graph
+ for i in range(0, len(speed[0])):
+ ax.bar(speed[0][i], speed[1][i], width=period, align="edge", color="#1f77b4")
+
+ # Save graph
+ fig.savefig(tmp.name, bbox_inches="tight", pad_inches=0.2)
+ file = discord.File(tmp.name, filename="image.png")
+
+ # Add content to embed
+ embed.description = f"**Countdown Channel:** <#{countdown.id}>\n\n"
+ embed.description += f"**Period Size:** {period}\n"
+ if (len(countdown.messages) > 1):
+ rate = (stats['total'] - stats['current'])/((countdown.messages[-1].timestamp - countdown.messages[0].timestamp) / period)
else:
- if (len(countdown.messages) == 0):
- embed.color = COLORS["error"]
- embed.description = "The countdown is empty."
- elif (period < 0.01):
- embed.color = COLORS["error"]
- embed.description = "The period cannot be less than 0.01 hours"
- else:
- # Get stats
- stats = countdown.progress()
- period = timedelta(hours=period)
- speed = countdown.speed(period)
-
- # Create figure
- fig, ax = plt.subplots()
- ax.set_xlabel("Time")
- ax.set_ylabel("Progress per Period")
- fig.autofmt_xdate()
-
- # Add data to graph
- for i in range(0, len(speed[0])):
- ax.bar(speed[0][i], speed[1][i], width=period, align="edge", color="#1f77b4")
-
- # Save graph
- fig.savefig(tmp.name, bbox_inches="tight", pad_inches=0.2)
- file = discord.File(tmp.name, filename="image.png")
-
- # Add content to embed
- embed.description = f"**Countdown Channel:** <#{countdown.id}>\n\n"
- embed.description += f"**Period Size:** {period}\n"
- if (len(countdown.messages) > 1):
- rate = (stats['total'] - stats['current'])/((countdown.messages[-1].timestamp - countdown.messages[0].timestamp) / period)
- else:
- rate = 0
- embed.description += f"**Average Progress per Period:** {round(rate):,}\n"
- embed.description += f"**Record Progress per Period:** {max(speed[1]):,}\n"
- embed.description += f"**Last Period Start:** {speed[0][-1]}\n"
- embed.description += f"**Progress during Last Period:** {speed[1][-1]:,}\n"
- embed.set_image(url="attachment://image.png")
+ rate = 0
+ embed.description += f"**Average Progress per Period:** {round(rate):,}\n"
+ embed.description += f"**Record Progress per Period:** {max(speed[1]):,}\n"
+ embed.description += f"**Last Period Start:** {speed[0][-1]}\n"
+ embed.description += f"**Progress during Last Period:** {speed[1][-1]:,}\n"
+ embed.set_image(url="attachment://image.png")
# Send embed
try:
diff --git a/src/bot.py b/src/bot.py
@@ -1,12 +1,13 @@
# Import dependencies
import discord
from discord.ext import commands
+import traceback
# Import modules
from src import analyticsCog, utilitiesCog
-from src.botUtilities import addMessage, COLORS, getCountdown, getPrefix
-from src.models import getSessionMaker
+from src.botUtilities import addMessage, COLORS, CountdownNotFound, ContributorNotFound, CommandError, getCountdown, getPrefix
+from src.models import getSessionMaker, EmptyCountdownError
@@ -70,10 +71,20 @@ class CountdownBot(commands.Bot):
async def on_command_error(self, ctx, error):
# Send error embed
- embed=discord.Embed(title="Error", description=str(error), color=COLORS["error"])
+ embed=discord.Embed(title=":warning: Error", description=str(error), color=COLORS["error"])
if (isinstance(error, commands.CommandNotFound)):
embed.description = f"Command not found: `{str(error)[9:-14]}`"
+ elif (isinstance(error.original, CountdownNotFound)):
+ embed.description = f"Countdown not found"
+ elif (isinstance(error.original, ContributorNotFound)):
+ embed.description = f"Contributor not found: `{error.original.args[0]}`"
+ elif (isinstance(error.original, EmptyCountdownError)):
+ embed.description = f"The countdown is empty"
+ elif (isinstance(error.original, CommandError)):
+ embed.description = error.original.args[0]
else:
+ # Unanticipated error
embed.description = str(error)
- embed.description += f"\nUse `{(await self.get_prefix(ctx))[0]}help` to view help information\n"
+ traceback.print_exception(type(error), error, error.__traceback__)
+ embed.description += f"\n\nUse `{(await self.get_prefix(ctx))[0]}help` to view help information"
await ctx.send(embed=embed)
diff --git a/src/botUtilities.py b/src/botUtilities.py
@@ -15,9 +15,15 @@ COLORS = {
# Error classes
+class CommandError(Exception):
+ """Raised when a command encounters an anticipated error"""
+ pass
class ContributorNotFound(Exception):
"""Raised when a matching countdown contributor cannot be found"""
pass
+class CountdownNotFound(Exception):
+ """Raised when a matching countdown cannot be found"""
+ pass
@@ -149,6 +155,11 @@ def getContextCountdown(session, ctx):
-------
Countdown
The countdown
+
+ Raises
+ ------
+ CountdownNotFound
+ If a matching countdown cannot be found
"""
if (isinstance(ctx.channel, discord.channel.TextChannel)):
@@ -165,7 +176,7 @@ def getContextCountdown(session, ctx):
firstMessage = session.query(Message).filter(Message.author_id == ctx.author.id).order_by(Message.timestamp).first()
if (firstMessage): return firstMessage.countdown
- raise Exception("Countdown channel not found")
+ raise CountdownNotFound()
diff --git a/src/models.py b/src/models.py
@@ -44,6 +44,10 @@ POINT_RULES = {
# Error classes
+class EmptyCountdownError(Exception):
+ """Raised when an action cannot be completed because the countdown is empty."""
+ pass
+
class MessageNotAllowedError(Exception):
"""Raised when someone posts twice in a row."""
pass
@@ -137,6 +141,10 @@ class Countdown(Base):
A list of contributor statistics.
"""
+ # Make sure countdown has started
+ if (len(self.messages) == 0):
+ raise EmptyCountdownError()
+
# Get contributors
authors = list(set([x.author_id for x in self.messages]))
@@ -170,8 +178,8 @@ class Countdown(Base):
"""
# Make sure countdown has at least two messages
- if (len(self.messages) < 2):
- return [[], []]
+ if (len(self.messages) == 0):
+ raise EmptyCountdownError()
# Initialize period data
periodEnd = self.messages[0].timestamp + timedelta(hours=self.timezone) + period
@@ -223,6 +231,10 @@ class Countdown(Base):
A 7x24 2D array containing the heatmap
"""
+ # Make sure countdown has started
+ if (len(self.messages) == 0):
+ raise EmptyCountdownError()
+
# Initialize result matrix
result = [[0 for i in range(24)] for j in range(7)]
@@ -255,8 +267,9 @@ class Countdown(Base):
The leaderboard.
"""
+ # Make sure countdown has started
if (len(self.messages) == 0):
- return []
+ raise EmptyCountdownError()
# Get list of prime numbers
curTest = 5
@@ -323,17 +336,15 @@ class Countdown(Base):
A dictionary containing countdown progress statistics.
"""
+ # Make sure countdown has started
+ if (len(self.messages) == 0):
+ raise EmptyCountdownError()
+
# Get basic statistics
- if (len(self.messages) > 0):
- total = self.messages[0].number
- current = self.messages[-1].number
- percentage = (total - current) / total * 100
- start = self.messages[0].timestamp
- else:
- total = 0
- current = 0
- percentage = 0
- start = datetime.utcnow()
+ total = self.messages[0].number
+ current = self.messages[-1].number
+ percentage = (total - current) / total * 100
+ start = self.messages[0].timestamp
# Get rate statistics
if (len(self.messages) > 1 and self.messages[-1].number == 0):
@@ -377,6 +388,10 @@ class Countdown(Base):
The countdown speed statistics.
"""
+ # Make sure countdown has started
+ if (len(self.messages) == 0):
+ raise EmptyCountdownError()
+
# Calculate speed statistics
data = [[], []]
periodStart = datetime(2018, 1, 1) # Starts on Monday, Jan 1st
diff --git a/src/utilitiesCog.py b/src/utilitiesCog.py
@@ -3,7 +3,7 @@ import discord
from discord.ext import commands
# Import modules
-from src.botUtilities import COLORS, getContextCountdown, getCountdown, loadCountdown
+from src.botUtilities import COLORS, CommandError, getContextCountdown, getCountdown, loadCountdown
from src.models import Countdown, Prefix, Reaction
@@ -23,46 +23,41 @@ class Utilities(commands.Cog):
"""
with self.databaseSessionMaker() as session:
- # Channel is already a countdown
+ # Check if channel is already a countdown
if (getCountdown(session, ctx.channel.id)):
- embed = discord.Embed(title="Error", description="This channel is already a countdown", color=COLORS["error"])
- await ctx.send(embed=embed)
-
- # Channel is a DM
- elif (not isinstance(ctx.channel, discord.channel.TextChannel)):
- embed = discord.Embed(title="Error", description="This command must be run inside a server", color=COLORS["error"])
- await ctx.send(embed=embed)
-
- # User isn't authorized
- elif (not ctx.message.author.guild_permissions.administrator):
- embed = discord.Embed(title="Error", description="You must be an administrator to turn a channel into a countdown", color=COLORS["error"])
- await ctx.send(embed=embed)
-
- # Channel is valid
- else:
- # Create countdown
- countdown = Countdown(
- id = ctx.channel.id,
- server_id = ctx.channel.guild.id,
- timezone = 0,
- prefixes = [Prefix(countdown_id=ctx.channel.id, value=x) for x in self.bot.prefixes],
- reactions = [],
- messages = [],
- )
-
- # Send initial response
- print(f"Activated {self.bot.get_channel(ctx.channel.id)} as a countdown")
- embed = discord.Embed(title=":clock3: Loading Countdown", description="@here This channel is now a countdown\nPlease wait to start counting", color=COLORS["embed"])
- msg = await ctx.send(embed=embed)
-
- # Load countdown
- await loadCountdown(self.bot, countdown)
- session.add(countdown)
- session.commit()
+ raise CommandError("This channel is already a countdown")
+
+ # Check if channel is a DM
+ if (not isinstance(ctx.channel, discord.channel.TextChannel)):
+ raise CommandError("This command must be run inside a server")
+
+ # Check if user isn't authorized
+ if (not ctx.message.author.guild_permissions.administrator):
+ raise CommandError("You must be an administrator to turn a channel into a countdown")
+
+ # Create countdown
+ countdown = Countdown(
+ id = ctx.channel.id,
+ server_id = ctx.channel.guild.id,
+ timezone = 0,
+ prefixes = [Prefix(countdown_id=ctx.channel.id, value=x) for x in self.bot.prefixes],
+ reactions = [],
+ messages = [],
+ )
+
+ # Send initial response
+ print(f"Activated {self.bot.get_channel(ctx.channel.id)} as a countdown")
+ embed = discord.Embed(title=":clock3: Loading Countdown", description="@here This channel is now a countdown\nPlease wait to start counting", color=COLORS["embed"])
+ msg = await ctx.send(embed=embed)
+
+ # Load countdown
+ await loadCountdown(self.bot, countdown)
+ session.add(countdown)
+ session.commit()
- # Send final response
- embed = discord.Embed(title=":white_check_mark: Countdown Activated", description="@here This channel is now a countdown\nYou may start counting!", color=COLORS["embed"])
- await msg.edit(embed=embed)
+ # Send final response
+ embed = discord.Embed(title=":white_check_mark: Countdown Activated", description="@here This channel is now a countdown\nYou may start counting!", color=COLORS["embed"])
+ await msg.edit(embed=embed)
@@ -77,15 +72,12 @@ class Utilities(commands.Cog):
# Make sure context is in a server
if (not isinstance(ctx.channel, discord.channel.TextChannel)):
- embed.color = COLORS["error"]
- embed.description = "This command must be run in a countdown channel or a server with a countdown channel"
- await ctx.send(embed=embed)
- return
+ raise CommandError("This command must be run in a countdown channel or a server with a countdown channel")
with self.databaseSessionMaker() as session:
# Get countdown channel
countdown = getContextCountdown(session, ctx)
-
+
# Get / set settings
if (key is None):
embed.description = f"**Countdown Channel:** <#{countdown.id}>\n"
@@ -98,17 +90,14 @@ class Utilities(commands.Cog):
for number in list(dict.fromkeys([x.number for x in countdown.reactions])):
embed.description += f"**-** #{number}: {', '.join([x.value for x in countdown.reactions if x.number == number])}\n"
elif (not ctx.message.author.guild_permissions.administrator):
- embed.color = COLORS["error"]
- embed.description = f"You must be an administrator to modify settings"
+ raise CommandError("You must be an administrator to modify settings")
elif (len(args) == 0):
- embed.color = COLORS["error"]
- embed.description = f"Please provide a value for the setting"
+ raise CommandError("Please provide a value for the setting")
elif (key in ["tz", "timezone"]):
try:
countdown.timezone = float(args[0])
except:
- embed.color = COLORS["error"]
- embed.description = f"Invalid timezone: {args[0]}"
+ raise CommandError(f"Invalid timezone: `{args[0]}`")
else:
embed.description = f"Timezone set to {countdown.getTimezone()}"
elif (key in ["prefix", "prefixes"]):
@@ -118,8 +107,7 @@ class Utilities(commands.Cog):
try:
number = int(args[0])
if (number < 0):
- embed.color = COLORS["error"]
- embed.description = f"Number must be greater than zero"
+ raise CommandError("Number must be greater than zero")
elif (len(args) == 1):
countdown.reactions = [x for x in countdown.reactions if x.number != number]
embed.description = f"Removed reactions for #{number}"
@@ -128,12 +116,9 @@ class Utilities(commands.Cog):
countdown.reactions += [Reaction(countdown_id=countdown.id, number=number, value=x) for x in args[1:]]
embed.description = f"Updated reactions for #{number}"
except:
- embed.color = COLORS["error"]
- embed.description = f"Invalid number: {args[0]}"
+ raise CommandError(f"Invalid number: `{args[0]}`")
else:
- embed.color = COLORS["error"]
- embed.description = f"Setting not found: `{key}`\n"
- embed.description += f"Use `{(await self.bot.get_prefix(ctx))[0]}help config` to view the list of settings"
+ raise CommandError(f"Setting not found: `{key}`")
# Save changes
session.commit()
@@ -150,27 +135,23 @@ class Utilities(commands.Cog):
"""
with self.databaseSessionMaker() as session:
- # Channel isn't a countdown
+ # Check if channel isn't a countdown
countdown = getCountdown(session, ctx.channel.id)
if (not countdown):
- embed = discord.Embed(title="Error", description="This channel isn't a countdown", color=COLORS["error"])
- await ctx.send(embed=embed)
+ raise CommandError("This channel isn't a countdown")
- # User isn't authorized
- elif (not ctx.author.guild_permissions.administrator):
- embed = discord.Embed(title="Error", description="You must be an administrator to deactivate a countdown channel", color=COLORS["error"])
- await ctx.send(embed=embed)
+ # Check if user isn't authorized
+ if (not ctx.author.guild_permissions.administrator):
+ raise CommandError("You must be an administrator to deactivate a countdown channel")
- # Channel is valid
- else:
- # Delete countdown
- session.delete(countdown)
- session.commit()
+ # Delete countdown
+ session.delete(countdown)
+ session.commit()
- # Send response
- print(f"Deactivated {self.bot.get_channel(ctx.channel.id)} as a countdown")
- embed = discord.Embed(title=":octagonal_sign: Countdown Deactivated", description="@here This channel is no longer a countdown", color=COLORS["embed"])
- await ctx.send(embed=embed)
+ # Send response
+ print(f"Deactivated {self.bot.get_channel(ctx.channel.id)} as a countdown")
+ embed = discord.Embed(title=":octagonal_sign: Countdown Deactivated", description="@here This channel is no longer a countdown", color=COLORS["embed"])
+ await ctx.send(embed=embed)
@@ -356,9 +337,7 @@ class Utilities(commands.Cog):
elif (command.lower() in ["s", "speed"]):
embed.description = help_text["speed"]
else:
- embed.color = COLORS["error"]
- embed.description = f"Command not found: `{command}`\n"
- embed.description += f"Use `{prefixes[0]}help` to view the list of commands"
+ raise CommandError(f"Command not found: `{command}`")
# Send embed
await ctx.send(embed=embed)
@@ -399,5 +378,4 @@ class Utilities(commands.Cog):
embed = discord.Embed(title=":white_check_mark: Countdown Cache Reloaded", description="Done! You may continue counting!", color=COLORS["embed"])
await msg.edit(embed=embed)
else:
- embed = discord.Embed(title="Error", description="This command must be used in a countdown channel", color = COLORS["error"])
- await ctx.channel.send(embed=embed)
+ raise CommandError("Countdown not found\nThis command must be used in a countdown channel")