This commit is contained in:
2025-10-28 15:42:26 +01:00
parent 020c686c81
commit 18d7f318f6
44 changed files with 7168 additions and 7137 deletions

View File

@@ -1,12 +1,12 @@
"""A collections of utilities used by Gwendolyn and her functions."""
__all__ = ["get_options", "get_credentials", "DatabaseFuncs", "EventHandler",
"ErrorHandler", "get_params", "log_this", "cap", "make_files",
"replace_multiple", "emoji_to_command"]
"ErrorHandler", "get_params", "log_this", "cap", "make_files",
"replace_multiple", "emoji_to_command"]
from .helper_classes import DatabaseFuncs
from .event_handlers import EventHandler, ErrorHandler
from .util_functions import (get_params, log_this, cap, make_files,
replace_multiple, emoji_to_command, long_strings,
sanitize, get_options, get_credentials, encode_id,
decode_id)
replace_multiple, emoji_to_command, long_strings,
sanitize, get_options, get_credentials, encode_id,
decode_id)

View File

@@ -3,15 +3,15 @@ Classes used to handle bot events and errors.
*Classes*
---------
EventHandler
ErrorHandler
EventHandler
ErrorHandler
"""
import traceback # Used to get the traceback of errors
import discord # Used to init discord.Game and discord.Status, as well
# as compare errors to discord errors and as typehints
# as compare errors to discord errors and as typehints
from discord.ext import commands # Used to compare errors with command
# errors
# errors
from interactions import SlashContext, ComponentContext
from gwendolyn_old.utils.util_functions import decode_id
@@ -19,88 +19,88 @@ from gwendolyn_old.exceptions import InvalidInteraction
class EventHandler():
"""
Handles bot events.
"""
Handles bot events.
*Methods*
---------
on_ready()
on_slash_command(ctx: interactions.SlashContext)
on_reaction_add(ctx: interactions.SlashContext)
"""
*Methods*
---------
on_ready()
on_slash_command(ctx: interactions.SlashContext)
on_reaction_add(ctx: interactions.SlashContext)
"""
def __init__(self, bot):
"""Initialize the handler."""
self.bot = bot
def __init__(self, bot):
"""Initialize the handler."""
self.bot = bot
async def on_ready(self):
"""Log and sets status when it logs in."""
await self.bot.database_funcs.imdb_commands()
name = self.bot.user.name
userid = str(self.bot.user.id)
logged_in_message = f"Logged in as {name}, {userid}"
self.bot.log(logged_in_message, level=25)
game = discord.Game("Use /help for commands")
async def on_ready(self):
"""Log and sets status when it logs in."""
await self.bot.database_funcs.imdb_commands()
name = self.bot.user.name
userid = str(self.bot.user.id)
logged_in_message = f"Logged in as {name}, {userid}"
self.bot.log(logged_in_message, level=25)
game = discord.Game("Use /help for commands")
online_status = discord.Status.online
await self.bot.change_presence(activity=game, status=online_status)
online_status = discord.Status.online
await self.bot.change_presence(activity=game, status=online_status)
async def on_slash_command(self, ctx: SlashContext):
"""Log when a slash command is given."""
if ctx.subcommand_name is not None:
subcommand = f" {ctx.subcommand_name} "
else:
subcommand = " "
async def on_slash_command(self, ctx: SlashContext):
"""Log when a slash command is given."""
if ctx.subcommand_name is not None:
subcommand = f" {ctx.subcommand_name} "
else:
subcommand = " "
if ctx.subcommand_group is not None:
sub_command_group = f"{ctx.subcommand_group} "
else:
sub_command_group = ""
if ctx.subcommand_group is not None:
sub_command_group = f"{ctx.subcommand_group} "
else:
sub_command_group = ""
args = " ".join([str(i) for i in ctx.args])
full_command = f"/{ctx.command}{subcommand}{sub_command_group}{args}"
log_message = f"{ctx.author.display_name} ran {full_command}"
self.bot.log(log_message, str(ctx.channel_id), level=25)
args = " ".join([str(i) for i in ctx.args])
full_command = f"/{ctx.command}{subcommand}{sub_command_group}{args}"
log_message = f"{ctx.author.display_name} ran {full_command}"
self.bot.log(log_message, str(ctx.channel_id), level=25)
async def on_component(self, ctx: ComponentContext):
"""Handle component interaction."""
info = decode_id(ctx.custom_id)
self.bot.log(f"Component action with info {info}")
channel = ctx.channel
author = str(ctx.author_id)
async def on_component(self, ctx: ComponentContext):
"""Handle component interaction."""
info = decode_id(ctx.custom_id)
self.bot.log(f"Component action with info {info}")
channel = ctx.channel
author = str(ctx.author_id)
if info[0].lower() == "plex":
if info[1].lower() == "movie":
await self.bot.other.plex.add_movie(
ctx.origin_message,
info[2],
not isinstance(channel, discord.DMChannel)
)
return
if info[0].lower() == "plex":
if info[1].lower() == "movie":
await self.bot.other.plex.add_movie(
ctx.origin_message,
info[2],
not isinstance(channel, discord.DMChannel)
)
return
elif info[1].lower() == "show":
await self.bot.other.plex.add_show(
ctx.origin_message,
info[2],
not isinstance(channel, discord.DMChannel)
)
else:
raise InvalidInteraction(ctx.custom_id, info)
elif info[1].lower() == "show":
await self.bot.other.plex.add_show(
ctx.origin_message,
info[2],
not isinstance(channel, discord.DMChannel)
)
else:
raise InvalidInteraction(ctx.custom_id, info)
elif info[0].lower() == "hangman" and author == info[2]:
if info[1].lower() == "guess":
await self.bot.games.hangman.guess(ctx, *info[3:])
elif info[1].lower() == "end":
await self.bot.games.hangman.stop(ctx, *info[3:])
else:
raise InvalidInteraction(ctx.custom_id, info)
elif info[0].lower() == "connectfour":
connect_four = self.bot.games.connect_four
if info[1].lower() == "place" and author == info[2]:
await connect_four.place_piece(
ctx,
info[3],
int(info[4]),
elif info[0].lower() == "hangman" and author == info[2]:
if info[1].lower() == "guess":
await self.bot.games.hangman.guess(ctx, *info[3:])
elif info[1].lower() == "end":
await self.bot.games.hangman.stop(ctx, *info[3:])
else:
raise InvalidInteraction(ctx.custom_id, info)
elif info[0].lower() == "connectfour":
connect_four = self.bot.games.connect_four
if info[1].lower() == "place" and author == info[2]:
await connect_four.place_piece(
ctx,
info[3],
int(info[4]),
[int(info[5]), int(info[6])],
int(info[7]),
ctx.author_id,

View File

@@ -3,7 +3,7 @@ Contains classes used for utilities.
*Classes*
---------
DatabaseFuncs()
DatabaseFuncs()
"""
import os # Used to test if files exist
import time # Used to test how long it's been since commands were synced
@@ -13,161 +13,161 @@ import discord # Used for type hints
class DatabaseFuncs():
"""
Manages database functions.
"""
Manages database functions.
*Methods*
*Methods*
---------
get_name(user_id: str) -> str
get_id(user_name: str) -> str
delete_game(game_type: str, channel: str)
wipe_games()
connect_four_reaction_test(message: discord.Message,
user: discord.User) -> bool
imdb_commands()
"""
def __init__(self, bot):
"""Initialize the class."""
self.bot = bot
def get_name(self, user_id: str):
"""
Get the name of a user you have the # id of.
*Parameters:
------------
user_id: str
The id of the user you want the name of. The format is
"#" + str(discord.User.id)
*Returns*
---------
get_name(user_id: str) -> str
get_id(user_name: str) -> str
delete_game(game_type: str, channel: str)
wipe_games()
connect_four_reaction_test(message: discord.Message,
user: discord.User) -> bool
imdb_commands()
user_name: str
The name of the user. If the user couldn't be found,
returns the user_id.
"""
user = self.bot.database["users"].find_one({"_id": user_id})
def __init__(self, bot):
"""Initialize the class."""
self.bot = bot
if user_id == f"#{self.bot.user.id}":
return_name = "Gwendolyn"
elif user is not None:
return_name = user["user name"]
else:
self.bot.log(f"Couldn't find user {user_id}")
return_name = user_id
def get_name(self, user_id: str):
"""
Get the name of a user you have the # id of.
return return_name
*Parameters:
------------
user_id: str
The id of the user you want the name of. The format is
"#" + str(discord.User.id)
def get_id(self, user_name: str):
"""
Get the id of a user you have the username of.
*Returns*
---------
user_name: str
The name of the user. If the user couldn't be found,
returns the user_id.
"""
user = self.bot.database["users"].find_one({"_id": user_id})
*Parameters:
------------
user_name: str
The name of the user you want the id of.
if user_id == f"#{self.bot.user.id}":
return_name = "Gwendolyn"
elif user is not None:
return_name = user["user name"]
else:
self.bot.log(f"Couldn't find user {user_id}")
return_name = user_id
*Returns*
---------
user_id: str
The id of the user in the format "#" +
str(discord.User.id). If the user couldn't be found,
returns the user_name.
"""
user_search = {"user name": re.compile(user_name, re.IGNORECASE)}
user = self.bot.database["users"].find_one(user_search)
return return_name
if user is not None:
return_id = user["_id"]
else:
self.bot.log("Couldn't find user "+user_name)
return_id = None
def get_id(self, user_name: str):
"""
Get the id of a user you have the username of.
return return_id
*Parameters:
------------
user_name: str
The name of the user you want the id of.
def delete_game(self, game_type: str, channel: str):
"""
Remove a game from the database.
*Returns*
---------
user_id: str
The id of the user in the format "#" +
str(discord.User.id). If the user couldn't be found,
returns the user_name.
"""
user_search = {"user name": re.compile(user_name, re.IGNORECASE)}
user = self.bot.database["users"].find_one(user_search)
*Parameters*
------------
game_type: str
The name of the collection the game is in, like
"hangman games", "blackjack games" etc.
channel: str
The channel id of the channel the game is on as a
string.
"""
self.bot.database[game_type].delete_one({"_id": channel})
if user is not None:
return_id = user["_id"]
else:
self.bot.log("Couldn't find user "+user_name)
return_id = None
def wipe_games(self):
"""Delete all running games and pull from git."""
game_types = [
"trivia questions",
"blackjack games",
"connect 4 games"
"hex games",
"wordle games"
]
for game_type in game_types:
self.bot.database[game_type].delete_many({})
return return_id
def connect_four_reaction_test(self, message: discord.Message,
user: discord.User):
"""
Test if the given message is the current connect four game.
def delete_game(self, game_type: str, channel: str):
"""
Remove a game from the database.
Also tests if the given user is the one who's turn it is.
*Parameters*
------------
game_type: str
The name of the collection the game is in, like
"hangman games", "blackjack games" etc.
channel: str
The channel id of the channel the game is on as a
string.
"""
self.bot.database[game_type].delete_one({"_id": channel})
*Parameters*
------------
message: discord.Message
The message to test.
user: discord.User
The user to test.
*Returns*
---------
: bool
Whether the given message is the current connect four
game and if the user who reacted is the user who's turn
it is.
"""
channel = message.channel
channel_search = {"_id": str(channel.id)}
game = self.bot.database["connect 4 games"].find_one(channel_search)
def wipe_games(self):
"""Delete all running games and pull from git."""
game_types = [
"trivia questions",
"blackjack games",
"connect 4 games"
"hex games",
"wordle games"
]
for game_type in game_types:
self.bot.database[game_type].delete_many({})
old_images_path = "gwendolyn/resources/games/old_images/"
file_path = old_images_path + f"connect_four{channel.id}"
if os.path.isfile(file_path):
with open(file_path, "r", encoding="utf-8") as file_pointer:
old_image = int(file_pointer.read())
else:
old_image = 0
def connect_four_reaction_test(self, message: discord.Message,
user: discord.User):
"""
Test if the given message is the current connect four game.
if message.id == old_image:
self.bot.log("They reacted to the connect_four game")
turn = game["turn"]
if user == game["players"][turn]:
valid_reaction = True
else:
self.bot.log("It wasn't their turn")
valid_reaction = False
else:
valid_reaction = False
Also tests if the given user is the one who's turn it is.
return valid_reaction
*Parameters*
------------
message: discord.Message
The message to test.
user: discord.User
The user to test.
*Returns*
---------
: bool
Whether the given message is the current connect four
game and if the user who reacted is the user who's turn
it is.
"""
channel = message.channel
channel_search = {"_id": str(channel.id)}
game = self.bot.database["connect 4 games"].find_one(channel_search)
old_images_path = "gwendolyn/resources/games/old_images/"
file_path = old_images_path + f"connect_four{channel.id}"
if os.path.isfile(file_path):
with open(file_path, "r", encoding="utf-8") as file_pointer:
old_image = int(file_pointer.read())
else:
old_image = 0
if message.id == old_image:
self.bot.log("They reacted to the connect_four game")
turn = game["turn"]
if user == game["players"][turn]:
valid_reaction = True
else:
self.bot.log("It wasn't their turn")
valid_reaction = False
else:
valid_reaction = False
return valid_reaction
async def imdb_commands(self):
"""Sync the slash commands with the discord API."""
collection = self.bot.database["last synced"]
last_synced = collection.find_one()
now = time.time()
if last_synced["last synced"] < now - 86400:
slash_command_list = await self.bot.slash.to_dict()
self.bot.log(f"Updating commands: {slash_command_list}")
await self.bot.slash.sync_all_commands()
id_number = last_synced["_id"]
query_filter = {"_id": id_number}
update = {"$set": {"last synced": now}}
collection.update_one(query_filter, update)
async def imdb_commands(self):
"""Sync the slash commands with the discord API."""
collection = self.bot.database["last synced"]
last_synced = collection.find_one()
now = time.time()
if last_synced["last synced"] < now - 86400:
slash_command_list = await self.bot.slash.to_dict()
self.bot.log(f"Updating commands: {slash_command_list}")
await self.bot.slash.sync_all_commands()
id_number = last_synced["_id"]
query_filter = {"_id": id_number}
update = {"$set": {"last synced": now}}
collection.update_one(query_filter, update)