🧹 Cleaning up cogs

This commit is contained in:
NikolajDanger
2021-03-31 16:53:37 +02:00
parent 92fe7913f7
commit aff29a8d91
10 changed files with 166 additions and 126 deletions

View File

@ -4,7 +4,7 @@ from discord.ext import commands
from discord_slash import SlashCommand
from pymongo import MongoClient
from funcs import Money, StarWars, Games, Other, LookupFuncs
from utils import Options, Credentials, logThis, makeFiles, databaseFuncs
from utils import Options, Credentials, logThis, makeFiles, databaseFuncs, EventHandler, ErrorHandler
class Gwendolyn(commands.Bot):
def __init__(self):
@ -25,6 +25,8 @@ class Gwendolyn(commands.Bot):
self.games = Games(self)
self.money = Money(self)
self.databaseFuncs = databaseFuncs(self)
self.eventHandler = EventHandler(self)
self.errorHandler = ErrorHandler(self)
intents = discord.Intents.default()
intents.members = True

View File

@ -1,4 +1,4 @@
import discord, traceback
import discord
from discord.ext import commands
class EventCog(commands.Cog):
@ -8,10 +8,7 @@ class EventCog(commands.Cog):
# Syncs commands, sets the game, and logs when the bot logs in
@commands.Cog.listener()
async def on_ready(self):
await self.bot.databaseFuncs.syncCommands()
self.bot.log("Logged in as "+self.bot.user.name+", "+str(self.bot.user.id), level = 25)
game = discord.Game("Use /help for commands")
await self.bot.change_presence(activity=game, status = discord.Status.online)
await self.bot.eventHandler.on_ready()
@commands.Cog.listener()
async def on_disconnect(self):
@ -20,38 +17,18 @@ class EventCog(commands.Cog):
# Logs when user sends a command
@commands.Cog.listener()
async def on_slash_command(self, ctx):
self.bot.log(f"{ctx.author.display_name} ran /{ctx.name}", str(ctx.channel_id), level = 25)
logMessage = f"{ctx.author.display_name} ran /{ctx.name}"
self.bot.log(logMessage, str(ctx.channel_id), level = 25)
# Logs if a command experiences an error
@commands.Cog.listener()
async def on_slash_command_error(self, ctx, error):
if isinstance(error, commands.CommandNotFound):
await ctx.send("That's not a command (error code 001)")
elif isinstance(error,commands.errors.MissingRequiredArgument):
self.bot.log(f"{error}",str(ctx.channel_id))
await ctx.send("Missing command parameters (error code 002). Try using `!help [command]` to find out how to use the command.")
else:
exception = traceback.format_exception(type(error), error, error.__traceback__)
stopAt = "\nThe above exception was the direct cause of the following exception:\n\n"
if stopAt in exception:
index = exception.index(stopAt)
exception = exception[:index]
exceptionString = "".join(exception)
self.bot.log([f"exception in /{ctx.name}", f"{exceptionString}"],str(ctx.channel_id), 40)
await ctx.send("Something went wrong (error code 000)")
await self.bot.errorHandler.on_slash_command_error(ctx, error)
# Logs if an error occurs
@commands.Cog.listener()
async def on_error(self, method):
exception = traceback.format_exc()
stopAt = "\nThe above exception was the direct cause of the following exception:\n\n"
if stopAt in exception:
index = exception.index(stopAt)
exception = exception[:index]
exceptionString = "".join(exception)
self.bot.log([f"exception in /{method}", f"{exceptionString}"], level = 40)
await self.bot.errorHandler.on_error(method)
def setup(bot):
bot.add_cog(EventCog(bot))

View File

@ -1,8 +1,6 @@
import discord, asyncio, json
from discord.ext import commands
from discord_slash import cog_ext
from discord_slash import SlashCommandOptionType as scot
from utils import getParams
params = getParams()
@ -15,73 +13,22 @@ class GamesCog(commands.Cog):
# Checks user balance
@cog_ext.cog_slash(**params["balance"])
async def balance(self, ctx):
await ctx.defer()
response = self.bot.money.checkBalance("#"+str(ctx.author.id))
if response == 1:
new_message = ctx.author.display_name + " has " + str(response) + " GwendoBuck"
else:
new_message = ctx.author.display_name + " has " + str(response) + " GwendoBucks"
await ctx.send(new_message)
await self.bot.money.sendBalance(ctx)
# Gives another user an amount of GwendoBucks
@cog_ext.cog_slash(**params["give"])
async def give(self, ctx, user, amount):
await ctx.defer()
username = user.display_name
if self.bot.databaseFuncs.getID(username) == None:
async for member in ctx.guild.fetch_members(limit=None):
if member.display_name.lower() == username.lower():
username = member.display_name
userID = "#" + str(member.id)
self.bot.database["users"].insert_one({"_id":userID,"user name":username,"money":0})
response = self.bot.money.giveMoney("#"+str(ctx.author.id),username,amount)
await ctx.send(response)
await self.bot.money.giveMoney(ctx, user, amount)
# Invest GwendoBucks in the stock market
@cog_ext.cog_slash(**params["invest"])
async def invest(self, ctx, parameters = "check"):
await ctx.defer()
response = self.bot.games.invest.parseInvest(parameters,"#"+str(ctx.author.id))
if response.startswith("**"):
responses = response.split("\n")
em = discord.Embed(title=responses[0],description="\n".join(responses[1:]),colour=0x00FF00)
await ctx.send(embed=em)
else:
await ctx.send(response)
await self.bot.games.invest.parseInvest(ctx, parameters)
# Runs a game of trivia
@cog_ext.cog_slash(**params["trivia"])
async def trivia(self, ctx, answer = ""):
await ctx.defer()
if answer == "":
question, options, correctAnswer = self.bot.games.trivia.triviaStart(str(ctx.channel_id))
if options != "":
results = "**"+question+"**\n"
for x, option in enumerate(options):
results += chr(x+97) + ") "+option+"\n"
await ctx.send(results)
await asyncio.sleep(60)
self.bot.games.trivia.triviaCountPoints(str(ctx.channel_id))
self.bot.databaseFuncs.deleteGame("trivia questions",str(ctx.channel_id))
self.bot.log("Time's up for the trivia question",str(ctx.channel_id))
await ctx.send("Time's up The answer was \""+chr(correctAnswer)+") "+options[correctAnswer-97]+"\". Anyone who answered that has gotten 1 GwendoBuck")
else:
await ctx.send(question, hidden=True)
elif answer in ["a","b","c","d"]:
response = self.bot.games.trivia.triviaAnswer("#"+str(ctx.author.id),str(ctx.channel_id),answer)
if response.startswith("Locked in "):
await ctx.send(f"{ctx.author.display_name} answered {answer}")
else:
await ctx.send(response)
else:
self.bot.log("I didn't understand that (error code 1101)",str(ctx.channel_id))
await ctx.send("I didn't understand that (error code 1101)")
await self.bot.games.trivia.triviaParse(ctx, answer)
class BlackjackCog(commands.Cog):

View File

@ -170,7 +170,6 @@ class Blackjack():
return hand, allStanding, preAllStanding
# When players try to hit
def blackjackHit(self,channel,user,handNumber = 0):
game = self.bot.database["blackjack games"].find_one({"_id":channel})
@ -224,7 +223,6 @@ class Blackjack():
self.bot.log(user+" tried to hit without being in the game")
return "You have to enter the game before you can hit"
# When players try to double down
def blackjackDouble(self,channel,user,handNumber = 0):
game = self.bot.database["blackjack games"].find_one({"_id":channel})
@ -562,7 +560,6 @@ class Blackjack():
return finalWinnings
def calcWinnings(self,hand, dealerValue, topLevel, dealerBlackjack, dealerBusted):
self.bot.log("Calculating winnings")
reason = ""
@ -703,7 +700,7 @@ class Blackjack():
else:
self.bot.log("Ending loop on round "+str(gameRound),str(channel.id))
async def parseBlackjack(self,content, ctx):
async def parseBlackjack(self, content, ctx):
# Blackjack shuffle variables
blackjackMinCards = 50
blackjackDecks = 4

View File

@ -1,3 +1,5 @@
import discord
class Invest():
def __init__(self, bot):
self.bot = bot
@ -103,35 +105,48 @@ class Invest():
else:
return "no"
def parseInvest(self, content: str, user : str):
if content.startswith("check"):
commands = content.split(" ")
async def parseInvest(self, ctx, parameters):
try:
await ctx.defer()
except:
self.bot.log("Defer failed")
user = f"#{ctx.author.id}"
if parameters.startswith("check"):
commands = parameters.split(" ")
if len(commands) == 1:
return self.getPortfolio(user)
response = self.getPortfolio(user)
else:
price = self.getPrice(commands[1])
if price == 0:
return f"{commands[1].upper()} is not traded on the american market."
response = f"{commands[1].upper()} is not traded on the american market."
else:
price = f"{price:,}".replace(",",".")
return f"The current {commands[1].upper()} stock is valued at **{price}** GwendoBucks"
response = f"The current {commands[1].upper()} stock is valued at **{price}** GwendoBucks"
elif content.startswith("buy"):
commands = content.split(" ")
elif parameters.startswith("buy"):
commands = parameters.split(" ")
if len(commands) == 3:
#try:
return self.buyStock(user,commands[1],int(commands[2]))
#except:
# return "The command must be given as \"/invest buy [stock] [amount of GwendoBucks to purchase with]\""
response = self.buyStock(user,commands[1],int(commands[2]))
else:
return "You must give both a stock name and an amount of gwendobucks you wish to spend."
response = "You must give both a stock name and an amount of gwendobucks you wish to spend."
elif content.startswith("sell"):
commands = content.split(" ")
elif parameters.startswith("sell"):
commands = parameters.split(" ")
if len(commands) == 3:
try:
return self.sellStock(user,commands[1],int(commands[2]))
response = self.sellStock(user,commands[1],int(commands[2]))
except:
return "The command must be given as \"/invest sell [stock] [amount of GwendoBucks to sell stocks for]\""
response = "The command must be given as \"/invest sell [stock] [amount of GwendoBucks to sell stocks for]\""
else:
return "You must give both a stock name and an amount of GwendoBucks you wish to sell stocks for."
response = "You must give both a stock name and an amount of GwendoBucks you wish to sell stocks for."
else:
response = "Incorrect parameters"
if response.startswith("**"):
responses = response.split("\n")
em = discord.Embed(title=responses[0],description="\n".join(responses[1:]),colour=0x00FF00)
await ctx.send(embed=em)
else:
await ctx.send(response)

View File

@ -14,6 +14,15 @@ class Money():
return userData["money"]
else: return 0
async def sendBalance(self, ctx):
await ctx.defer()
response = self.checkBalance("#"+str(ctx.author.id))
if response == 1:
new_message = ctx.author.display_name + " has " + str(response) + " GwendoBuck"
else:
new_message = ctx.author.display_name + " has " + str(response) + " GwendoBucks"
await ctx.send(new_message)
# Adds money to the account of a user
def addMoney(self,user,amount):
self.bot.log("adding "+str(amount)+" to "+user+"'s account")
@ -26,26 +35,39 @@ class Money():
self.database["users"].insert_one({"_id":user,"user name":self.bot.databaseFuncs.getName(user),"money":amount})
# Transfers money from one user to another
def giveMoney(self,user,targetUser,amount):
userData = self.database["users"].find_one({"_id":user})
targetUser = self.bot.databaseFuncs.getID(targetUser)
async def giveMoney(self, ctx, user, amount):
try:
await ctx.defer()
except:
self.bot.log("Defer failed")
username = user.display_name
if self.bot.databaseFuncs.getID(username) == None:
async for member in ctx.guild.fetch_members(limit=None):
if member.display_name.lower() == username.lower():
username = member.display_name
userID = "#" + str(member.id)
newUser = {"_id":userID,"user name":username,"money":0}
self.bot.database["users"].insert_one(newUser)
userData = self.database["users"].find_one({"_id":f"#{ctx.author.id}"})
targetUser = self.bot.databaseFuncs.getID(username)
if amount > 0:
if targetUser != None:
if userData != None:
if userData["money"] >= amount:
self.addMoney(user,-1 * amount)
self.addMoney(f"#{ctx.author.id}",-1 * amount)
self.addMoney(targetUser,amount)
return "Transferred "+str(amount)+" GwendoBucks to "+self.bot.databaseFuncs.getName(targetUser)
await ctx.send(f"Transferred {amount} GwendoBucks to {username}")
else:
self.bot.log("They didn't have enough GwendoBucks (error code 1223b)")
return "You don't have that many GwendoBucks (error code 1223b)"
self.bot.log("They didn't have enough GwendoBucks")
await ctx.send("You don't have that many GwendoBucks")
else:
self.bot.log("They didn't have enough GwendoBucks (error code 1223a)")
return "You don't have that many GwendoBucks (error code 1223a)"
self.bot.log("They didn't have enough GwendoBucks")
await ctx.send("You don't have that many GwendoBuck")
else:
self.bot.log("They weren't in the system")
return "The target doesn't exist"
await ctx.send("The target doesn't exist")
else:
self.bot.log("They tried to steal")
return "Yeah, no. You can't do that"
await ctx.send("Yeah, no. You can't do that")

View File

@ -1,6 +1,7 @@
import json
import urllib
import random
import asyncio
class Trivia():
def __init__(self, bot):
@ -83,3 +84,38 @@ class Trivia():
self.bot.log("Couldn't find the question (error code 1102)")
return None
async def triviaParse(self, ctx, answer):
try:
await ctx.defer()
except:
self.bot.log("defer failed")
if answer == "":
question, options, correctAnswer = self.triviaStart(str(ctx.channel_id))
if options != "":
results = "**"+question+"**\n"
for x, option in enumerate(options):
results += chr(x+97) + ") "+option+"\n"
await ctx.send(results)
await asyncio.sleep(60)
self.triviaCountPoints(str(ctx.channel_id))
self.bot.databaseFuncs.deleteGame("trivia questions",str(ctx.channel_id))
self.bot.log("Time's up for the trivia question",str(ctx.channel_id))
await ctx.send("Time's up The answer was \""+chr(correctAnswer)+") "+options[correctAnswer-97]+"\". Anyone who answered that has gotten 1 GwendoBuck")
else:
await ctx.send(question, hidden=True)
elif answer in ["a","b","c","d"]:
response = self.triviaAnswer("#"+str(ctx.author.id), str(ctx.channel_id), answer)
if response.startswith("Locked in "):
await ctx.send(f"{ctx.author.display_name} answered {answer})")
else:
await ctx.send(response)
else:
self.bot.log("I didn't understand that (error code 1101)",str(ctx.channel_id))
await ctx.send("I didn't understand that (error code 1101)")

View File

@ -84,7 +84,7 @@ All the Python code should follow the [PEP 8 guidelines](https://www.python.org/
Code called by a command should not have `try` and `except` statements. All errors should be raised to the `on_command_error()` or `Command.error()` functions, where they can be dealt with.
## Cogs
The `Command` methods in cogs should only exist to perform small tasks or call code from elsewhere in the Gwendolyn code. Therefore, a single `Command` method should not contain more than 3 lines of code and should not use any modules other than `Discord.py` and the Gwendolyn modules.
The `Command` methods in cogs should only exist to perform small tasks or call code from elsewhere in the Gwendolyn code. Therefore, a single `Command` method should not contain more than 3 lines of code and should not use any modules other than `Discord.py` and the Gwendolyn modules. If a cog method calls a function in Gwendolyn, ctx must be passed, and the function should handle sending messages.
## Codebase Management
### Folders
@ -102,11 +102,11 @@ Things you should know about the logging:
+ The function can take either a list of strings or a string as its first parameter. If the parameter is a string, it is converted to a list of 1 string.
+ The first string in the list is printed. All strings in the list are logged to the log-file.
+ If the list is longer than 1 string, `(details in log)` is added to the printed string.
+ The level parameter is 20 by default, which means the level is `INFO`. 40 corresponds to a level of `ERROR`, and 10 corresponds to a level of `DEBUG`. Only use these levels when logging.
+ Logs of level `DEBUG` are not printed.
+ Logs of level `ERROR` should only be created in the `on_command_error()` or `Command.error()` functions.
+ The level parameter is 20 by default, which means the level is `INFO`. 40 corresponds to a level of `ERROR`, and 25 corresponds to `print`.
+ Logs of level `INFO` are not printed.
+ Logs of level `ERROR` should only be created in the `on_command_error()`, `on_error()` or `Command.error()` functions.
### Logging rules
1. Never call the `logThis()` function from `/utils/utilFuncs/`. Always call `bot.log`.
1. The `on_slash_command()` and `on_ready()` events are the only times log should be called at level 20.`DEBUG` level logs should be used for all other logging.
1. The `on_slash_command()` and `on_ready()` events are the only times log should be called at level 25. `INFO` level logs should be used for all other logging.
1. Always provide the channel id if available. Although you shouldn't pass the channel id to a function purely to use it in logs.

View File

@ -1,6 +1,7 @@
"""A collections of utilities used by Gwendolyn and her functions"""
__all__ = ["Options", "Credentials", "databaseFuncs", "getParams", "logThis", "cap", "makeFiles", "replaceMultiple", "emojiToCommand"]
__all__ = ["Options", "Credentials", "databaseFuncs", "EventHandler", "ErrorHandler", "getParams", "logThis", "cap", "makeFiles", "replaceMultiple", "emojiToCommand"]
from .helperClasses import Options, Credentials, databaseFuncs
from .eventHandlers import EventHandler, ErrorHandler
from .utilFunctions import getParams, logThis, cap, makeFiles, replaceMultiple, emojiToCommand

43
utils/eventHandlers.py Normal file
View File

@ -0,0 +1,43 @@
import discord, traceback
from discord.ext import commands
class EventHandler():
def __init__(self, bot):
self.bot = bot
async def on_ready(self):
await self.bot.databaseFuncs.syncCommands()
self.bot.log("Logged in as "+self.bot.user.name+", "+str(self.bot.user.id), level = 25)
game = discord.Game("Use /help for commands")
await self.bot.change_presence(activity=game, status = discord.Status.online)
class ErrorHandler():
def __init__(self, bot):
self.bot = bot
async def on_slash_command_error(self, ctx, error):
if isinstance(error, commands.CommandNotFound):
await ctx.send("That's not a command (error code 001)")
elif isinstance(error,commands.errors.MissingRequiredArgument):
self.bot.log(f"{error}",str(ctx.channel_id))
await ctx.send("Missing command parameters (error code 002). Try using `!help [command]` to find out how to use the command.")
else:
exception = traceback.format_exception(type(error), error, error.__traceback__)
stopAt = "\nThe above exception was the direct cause of the following exception:\n\n"
if stopAt in exception:
index = exception.index(stopAt)
exception = exception[:index]
exceptionString = "".join(exception)
self.bot.log([f"exception in /{ctx.name}", f"{exceptionString}"],str(ctx.channel_id), 40)
await ctx.send("Something went wrong (error code 000)")
async def on_error(self, method):
exception = traceback.format_exc()
stopAt = "\nThe above exception was the direct cause of the following exception:\n\n"
if stopAt in exception:
index = exception.index(stopAt)
exception = exception[:index]
exceptionString = "".join(exception)
self.bot.log([f"exception in /{method}", f"{exceptionString}"], level = 40)