diff --git a/bot.py b/bot.py index 5b7f60f..aa13409 100644 --- a/bot.py +++ b/bot.py @@ -13,18 +13,11 @@ def __init__(self, intents: discord.Intents) -> None: self.prefix = "!" self.prefix_length = len(self.prefix) self.storage = StorageManagement() - + # Example of adding a custom config file, see below imported class # from storage_management import ConfigManagement # self.config = ConfigManagement() - # Initialize the command registry - from command_registry import registry - self.registry = registry - self.registry.set_instance(self) - self.registry.register_commands() - print("The bot has been initialized with the following commands: " + ", ".join(self.registry.get_command_names())) - # Initialize event registry from event_registry import event_registry self.event_registry = event_registry @@ -32,6 +25,13 @@ def __init__(self, intents: discord.Intents) -> None: self.event_registry.register_events() print("The bot has been initialized with the following events: " + ", ".join(self.event_registry.get_all_event_handlers())) + # Initialize the command registry + from command_registry import registry + self.registry = registry + self.registry.set_instance(self) + self.registry.register_commands() + print("The bot has been initialized with the following commands: " + ", ".join(self.registry.get_command_names())) + # Permissions for the muted role and for the default role self.muted_permissions = discord.PermissionOverwrite( send_messages=False, @@ -46,7 +46,7 @@ def __init__(self, intents: discord.Intents) -> None: ) # Start the discord client discord.Client.__init__(self, intents=intents) - + async def event_template(self, *args, **kwargs) -> None: """ The template event function used to replicate event functions dynamically. See event_registry.EventRegistry.register_events() where setattr() is used to add event handlers to this class @@ -58,18 +58,18 @@ async def event_template(self, *args, **kwargs) -> None: for event_handler in event_handlers: handler = event_handler(self) await handler.handle(*args, **kwargs) - + """ DISCORD CLIENT EVENTS START HERE (DEPRECATED, USE EVENT HANDLERS!) """ - + async def on_guild_join(self, guild: discord.Guild) -> None: print(f"Adding a guild to the bot's system since they invited us. Guild name: {guild.name}") await self.setup_guild(guild) - + async def on_guild_remove(self, guild: discord.Guild) -> None: print(f"Removing guild from guild storage since they removed the bot. Guild name: {guild.name}") self.storage.settings.pop(guild.id) await self.storage.write_file_to_disk() - + async def on_guild_channel_create(self, channel: discord.abc.GuildChannel) -> None: guild = channel.guild guild_id = str(guild.id) @@ -79,7 +79,7 @@ async def on_guild_channel_create(self, channel: discord.abc.GuildChannel) -> No await channel.set_permissions(target=muted_role, overwrite=self.muted_permissions) """ DISCORD CLIENT EVENTS END HERE (DEPRECATED, USE EVENT HANDLERS!) """ - + async def setup_guild(self, guild: discord.Guild) -> None: # Add the guild to the settings file if it doesn't exist if not await self.storage.has_guild(guild.id): @@ -90,7 +90,7 @@ async def setup_guild(self, guild: discord.Guild) -> None: await self.add_muted_role_to_channels(guild) # Create the log channel if it doesn't exist await self.create_log_channel(guild) - + async def check_for_muted_role(self, guild: discord.Guild) -> None: guild_id = str(guild.id) # Get the muted role ID from disk and try to get it from discord @@ -101,7 +101,7 @@ async def check_for_muted_role(self, guild: discord.Guild) -> None: muted_role = await guild.create_role(name="muted") self.storage.settings["guilds"][guild_id]["muted_role_id"] = muted_role.id await self.storage.write_file_to_disk() - + async def add_muted_role_to_channels(self, guild: discord.Guild) -> None: guild_id = str(guild.id) # Get the muted role ID from disk and then get it from discord diff --git a/events/member.py b/events/member.py index 0990075..8c92451 100644 --- a/events/member.py +++ b/events/member.py @@ -14,7 +14,7 @@ def __init__(self, client_instance: ModerationBot) -> None: self.client = client_instance self.storage = self.client.storage self.event = "on_member_join" - + async def handle(self, member: discord.abc.User, *args, **kwargs) -> None: guild = member.guild @@ -45,7 +45,7 @@ async def handle(self, member: discord.abc.User, *args, **kwargs) -> None: else: # Mute is not expired. Re-add it to the offender await user.add_roles(muted_role, reason="Remuted user since they had an active mute when they rejoined the server") - + for user_id in mutes_to_remove: self.storage.settings["guilds"][guild_id]["muted_users"].pop(str(user_id)) await self.storage.write_file_to_disk() @@ -56,13 +56,13 @@ def __init__(self, client_instance: ModerationBot) -> None: self.client = client_instance self.storage = self.client.storage self.event = "on_member_ban" - + async def handle(self, guild: discord.Guild, *args, **kwargs) -> None: guild_id = str(guild.id) log_channel_id = int(self.storage.settings["guilds"][guild_id]["log_channel_id"]) log_channel = guild.get_channel(log_channel_id) - + # Get the actions we already logged recently logged_actions = [] async for message in log_channel.history(limit=25): @@ -70,7 +70,7 @@ async def handle(self, guild: discord.Guild, *args, **kwargs) -> None: for field in embed.fields: if field.name == "**Audit Log ID**": logged_actions.append(int(field.value.replace("`", ""))) - + # Get recent ban actions async for entry in guild.audit_logs(action=discord.AuditLogAction.ban, limit=5): # If the entry was made by the bot or it's entry ID has already been logged, skip it @@ -92,13 +92,13 @@ def __init__(self, client_instance: ModerationBot) -> None: self.client = client_instance self.storage = self.client.storage self.event = "on_member_remove" - + async def handle(self, guild: discord.Guild, *args, **kwargs) -> None: guild_id = str(guild.id) log_channel_id = int(self.storage.settings["guilds"][guild_id]["log_channel_id"]) log_channel = guild.get_channel(log_channel_id) - + # Get the actions we already logged recently logged_actions = [] async for message in log_channel.history(limit=25): diff --git a/events/message.py b/events/message.py index 34c3d00..10aa422 100644 --- a/events/message.py +++ b/events/message.py @@ -12,7 +12,7 @@ class MessageEvent(EventHandler): def __init__(self, client_instance: ModerationBot) -> None: self.client = client_instance self.event = "on_message" - + async def handle(self, message: discord.Message, *args, **kwargs) -> None: # Get the user from the message user = message.author @@ -37,7 +37,7 @@ class MessageDeleteEvent(EventHandler): def __init__(self, client_instance: ModerationBot) -> None: self.client = client_instance self.event = "on_message_delete" - + async def handle(self, message: discord.Message, *args, **kwargs) -> None: # Ignore deletes of bot messages or messages from ourselves if message.author == self.client.user or message.author.bot: @@ -49,7 +49,7 @@ async def handle(self, message: discord.Message, *args, **kwargs) -> None: await embed_builder.add_field(name="**Message**", value=f"`{message.content}`") await embed_builder.add_field(name="**Created at**", value=f"`{message.created_at}`") embed = await embed_builder.get_embed() - + # Message the log channel the embed of the deleted message guild_id = str(message.guild.id) log_channel_id = int(self.client.storage.settings["guilds"][guild_id]["log_channel_id"]) diff --git a/events/ready.py b/events/ready.py index 8652ad2..05b262e 100644 --- a/events/ready.py +++ b/events/ready.py @@ -11,7 +11,7 @@ class ReadyEvent(EventHandler): def __init__(self, client_instance: ModerationBot): self.client = client_instance self.event = "on_ready" - + async def handle(self, *args, **kwargs) -> None: print(f"Logged in as {self.client.user}") # Start the storage management and setup the guilds we are connected to. diff --git a/helpers/embed_builder.py b/helpers/embed_builder.py index 96e002f..be32050 100644 --- a/helpers/embed_builder.py +++ b/helpers/embed_builder.py @@ -20,7 +20,7 @@ def __init__(self, event: str) -> None: } self.embed = embeds.get(event) or discord.Embed(title=event) - async def add_field(self, name: str, value: str, inline: Optional[bool]=False) -> None: + async def add_field(self, name: str, value: str, inline: Optional[bool] = False) -> None: """Add a field to the embed Args: diff --git a/helpers/misc_functions.py b/helpers/misc_functions.py index 688c08d..07a70d2 100644 --- a/helpers/misc_functions.py +++ b/helpers/misc_functions.py @@ -1,5 +1,7 @@ from typing import Union + from discord import Member + from storage_management import StorageManagement @@ -55,7 +57,7 @@ def is_valid_duration(duration: Union[int, str]) -> bool: return False else: return False - + def parse_duration(string: str) -> int: """Parses a duration in seconds from a duration string @@ -86,8 +88,8 @@ def parse_duration(string: str) -> int: return sum(nums) else: return -1 - - + + def author_is_admin(author: Member) -> bool: """Checks if the author is an administrator diff --git a/storage_management.py b/storage_management.py index c92457a..89e37fd 100644 --- a/storage_management.py +++ b/storage_management.py @@ -7,7 +7,6 @@ class JsonFileManager: """ JsonFileManager class handles basic saving and loading of a json based settings file """ def __init__(self): - __location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__))) self.file_path = "" self.settings = None @@ -63,7 +62,7 @@ async def create_file(self) -> None: "guilds": {} } await self.write_file_to_disk() - + async def has_guild(self, guild_id) -> bool: guild_id = str(guild_id) if self.settings["guilds"].get(guild_id) is not None: diff --git a/tasks/check_punishments.py b/tasks/check_punishments.py index c0ee4cb..24ba59f 100644 --- a/tasks/check_punishments.py +++ b/tasks/check_punishments.py @@ -12,7 +12,7 @@ async def check_punishments(client): log_channel_id = int(client.storage.settings["guilds"][guild_id]["log_channel_id"]) muted_role = guild.get_role(muted_role_id) log_channel = guild.get_channel(log_channel_id) - + # Get the muted users for the server muted_users = client.storage.settings["guilds"][guild_id]["muted_users"] mutes_to_remove = [] @@ -28,20 +28,20 @@ async def check_punishments(client): continue await user.remove_roles(muted_role, reason="Temp mute expired.") mutes_to_remove.append(user_id) - + # Build a mute expire embed and message it to the log channel embed_builder = EmbedBuilder(event="muteexpire") await embed_builder.add_field(name="**Unmuted user**", value=f"`{user.name}`") await embed_builder.add_field(name="**Mute duration**", value=f"`{normal_duration}`") embed = await embed_builder.get_embed() await log_channel.send(embed=embed) - + # Loop over all the mutes to remove and remove them from the storage. # (This is done aftewards since if we do it in the loop, python complains the dict size changed) for user_id in mutes_to_remove: client.storage.settings["guilds"][guild_id]["muted_users"].pop(str(user_id)) await client.storage.write_file_to_disk() - + # Not added yet so I left it blank for now banned_users = client.storage.settings["guilds"][guild_id]["banned_users"] bans_to_remove = [] @@ -57,14 +57,14 @@ async def check_punishments(client): continue await guild.unban(user, reason="Temp ban expired") bans_to_remove.append(user_id) - + # Build a ban expire embed and message it to the log channel. embed_builder = EmbedBuilder(event="banexpire") await embed_builder.add_field(name="**Unbanned user**", value=f"`{user.name}`") await embed_builder.add_field(name="**Ban duration**", value=f"`{normal_duration}`") embed = await embed_builder.get_embed() await log_channel.send(embed=embed) - + # Loop over all the mutes to remove and remove them from the storage. # (This is done aftewards since if we do it in the loop, python complains the dict size changed) for user_id in bans_to_remove: