Skip to content
This repository was archived by the owner on Feb 7, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7858e39
Add autoresponder config data during serverconfig generation
notsniped Oct 6, 2024
a090a87
Add heading comments to differentiate `fetch` and `set` functions
notsniped Oct 6, 2024
098f05c
Switch serverconfig autoresponder data type from `list` to `dict`
notsniped Oct 7, 2024
7467086
Make framework module functions for autoresponder configuration manag…
notsniped Oct 7, 2024
b2f29b8
Add command for adding new autoresponder configurations
notsniped Oct 7, 2024
331fbd7
Add a command to remove an existing autoresponder configuration
notsniped Oct 7, 2024
1ce692e
Add missing decorator symbols for some commands
notsniped Oct 7, 2024
118ec55
Add emojis to some embed responses in `autoresponder_remove`
notsniped Oct 7, 2024
5e9efcd
Shorten the description for the option `trigger_condition` in `/autor…
notsniped Oct 7, 2024
85b7ee0
Switch `active_channels` to `active_channel`
notsniped Oct 7, 2024
1f5013d
Use channel `id` property when setting active autoresponder channel
notsniped Oct 7, 2024
cf16c88
Prioritize checks for function error codes before continuing with suc…
notsniped Oct 7, 2024
a2ae62f
Prioritize checks for function error codes before continuing with suc…
notsniped Oct 7, 2024
3e397a9
Add default values for some args
notsniped Oct 7, 2024
4e8b52d
Add `/autoresponder_list` to allow users to view a list of all autore…
notsniped Oct 7, 2024
099fa1d
Add random todo note
notsniped Oct 7, 2024
ac5eb00
Send warning message if an autoresponder already exists with the same…
notsniped Oct 7, 2024
0583a8f
Fix issue where `/autoresponder_add` would crash if `active_channel` …
notsniped Oct 7, 2024
29f35ef
Remove a reference todo note
notsniped Oct 7, 2024
de3c496
Add autoresponder event trigger system to main code
notsniped Oct 8, 2024
b131da3
Move all autoresponder commands to a slash command group
notsniped Oct 8, 2024
5e812a3
Remove a bunch of extra newlines
notsniped Oct 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions cogs/serverconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,128 @@ async def verify(self, ctx: ApplicationContext, verification_code: int):
json.dump(self.verification_db, f, indent=4)

return await ctx.respond(f"You have been successfully verified in **{vcode_guild.name}**!")

# Autoresponder Configuration Commands
autoresponder_commands = SlashCommandGroup(name="autoresponder", description="Commands related to the management of server text-based autoresponders.")

@autoresponder_commands.command(
name="autoresponder_add",
description="Add a new text-based autoresponder to your server."
)
@option(name="autoresponder_name", description="The name (id) of the autoresponder.", type=str)
@option(name="text_trigger", description="The text on which the autoresponder is triggered.", type=str)
@option(name="text_response", description="The response you want the bot to send, when triggered.", type=str)
@option(name="trigger_condition", description="How do you want the autoresponder to be triggered?", type=str, choices=["MATCH_MESSAGE", "WITHIN_MESSAGE"])
@option(name="active_channel", description="In which channel do you want the autoresponder to be active?", type=discord.TextChannel, default=None)
@option(name="match_case", description="Do you want the trigger to be case-sensitive?", type=bool, default=False)
async def autoresponder_add(self, ctx: ApplicationContext, autoresponder_name: str, text_trigger: str, text_response: str, trigger_condition: str, active_channel: discord.TextChannel = None, match_case: bool = False):
"""Add a new text-based autoresponder to your server."""
if not ctx.author.guild_permissions.manage_messages:
return await ctx.respond("You can't use this command! You need the `Manage Messages` permission to run this.", ephemeral=True)
result_code = serverconf.add_autoresponder(
ctx.guild.id,
autoresponder_name=autoresponder_name,
autoresponder_trigger=text_trigger,
autoresponder_text=text_response,
autoresponder_trigger_condition=trigger_condition,
channel=active_channel.id if active_channel is not None else None,
match_case=match_case
)
if result_code == 1:
localembed = discord.Embed(
title=":warning: An Autoresponder Already Exists With This Name",
description="Try again using a different name, or remove the existing autoresponder and run this command again.",
color=discord.Color.orange()
)
return await ctx.respond(embed=localembed)
localembed = discord.Embed(
title=":white_check_mark: Autoresponder Successfully Created",
description=f"Autoresponder Name: `{autoresponder_name}`\n\nYou may use the autoresponder name to reference this autoresponder, for editing or deleting.",
color=discord.Color.green()
)
localembed.add_field(name="Text Trigger", value=text_trigger)
localembed.add_field(name="Bot Response", value=text_response)
localembed.add_field(name="Autoresponder Trigger Condition", value=trigger_condition)
if active_channel == None:
localembed.add_field(name="Active Channel", value="all channels")
else:
localembed.add_field(name="Active Channel", value=f"<#{active_channel.id}>")
localembed.add_field(name="Match Case?", value=match_case)
await ctx.respond(embed=localembed)

@autoresponder_commands.command(
name="autoresponder_remove",
description="Remove an existing autoresponder from your server."
)
@option(name="autoresponder_name", description="The name of the autoresponder you want to remove.", type=str)
async def autoresponder_remove(self, ctx: ApplicationContext, autoresponder_name: str):
"""Remove an existing autoresponder from your server."""
if not ctx.author.guild_permissions.manage_messages:
return await ctx.respond("You can't use this command! You need the `Manage Messages` permission to run this.", ephemeral=True)
result_code = serverconf.remove_autoresponder(ctx.guild.id, autoresponder_name)
if result_code == 1:
localembed = discord.Embed(title=":x: Failed to Remove Autoresponder", description=f"You don't have an autoresponder set with the name `{autoresponder_name}`.", color=discord.Color.red())
return await ctx.respond(embed=localembed)
elif result_code == 2:
localembed = discord.Embed(
title=":grey_question: No Autoresponders Set",
description=f"You don't have any autoresponders you can remove, let alone something with the name `{autoresponder_name}`.",
color=discord.Color.orange()
)
return await ctx.respond(embed=localembed)
localembed = discord.Embed(
title=f":white_check_mark: Autoresponder `{autoresponder_name}` Successfully Removed",
description="The bot will now not respond to this autoresponder's trigger.",
color=discord.Color.green()
)
await ctx.respond(embed=localembed)

@autoresponder_commands.command(
name="autoresponder_list",
description="View a list of all the autoresponders in the server, or info on a specific autoresponder."
)
@option(name="autoresponder_name", description="Which autoresponder do you want to view information about?", type=str, default=None)
async def autoresponder_list(self, ctx: ApplicationContext, autoresponder_name: str = None):
"""View a list of all the autoresponders in the server, or view specific information on an autoresponder."""
if not ctx.author.guild_permissions.manage_messages:
return await ctx.respond("You can't use this command! You need the `Manage Messages` permission to run this.", ephemeral=True)

# For List of All Autoresponders
if autoresponder_name == None:
autoresponders_list = serverconf.fetch_autoresponder_configuration(ctx.guild.id).keys()
if autoresponders_list == []:
localembed = discord.Embed(
title=":grey_question: No Autoresponders Set",
description=f"There are no autoresponders to show here...",
color=discord.Color.orange()
)
return await ctx.respond(embed=localembed)
parsed_output = str()
sr = 0
for key in autoresponders_list:
sr += 1
parsed_output += f"{sr}. `{key}`"
localembed = discord.Embed(title=f"Autoresponders List for **{ctx.guild}**", description=parsed_output, color=discord.Color.random())
localembed.set_footer(text="Run /autoresponder_list <autoresponder_name> to get more information on a specific autoresponder.")
await ctx.respond(embed=localembed)

# For Specific Autoresponder Configuration
else:
if autoresponder_name in serverconf.fetch_autoresponder_configuration(ctx.guild.id).keys():
autoresponder_data: dict = serverconf.fetch_autoresponder_configuration(ctx.guild.id, autoresponder_name=autoresponder_name)
localembed = discord.Embed(title=f"Information on Autoresponder `{autoresponder_name}`")
localembed.add_field(name="Text Trigger", value=autoresponder_data["autoresponder_trigger"])
localembed.add_field(name="Bot Response", value=autoresponder_data["autoresponder_text"])
localembed.add_field(name="Autoresponder Trigger Condition", value=autoresponder_data["autoresponder_trigger_condition"])
if autoresponder_data["active_channel"] == None:
localembed.add_field(name="Active Channel", value="all channels")
else:
localembed.add_field(name="Active Channel", value=f"<#{autoresponder_data['active_channel']}>")
localembed.add_field(name="Match Case?", value=autoresponder_data["match_case"])
await ctx.respond(embed=localembed)
else:
localembed = discord.Embed(title=":x: No Autoresponder Found", description=f"You don't have an autoresponder set with the name `{autoresponder_name}`.", color=discord.Color.red())
return await ctx.respond(embed=localembed)

def setup(bot):
bot.add_cog(ServerConfig(bot))
Expand Down
52 changes: 51 additions & 1 deletion framework/isobot/db/serverconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

# Imports
import json
from typing_extensions import Literal, Union
from framework.isobot.colors import Colors as colors

# Functions
Expand Down Expand Up @@ -34,7 +35,10 @@ def generate(self, server_id: int) -> int:
"message": None
},
"level_up_override_channel": None,
"verification_role": None
"verification_role": None,
"autoresponder": {

}
}
self.save(serverconf)
return 0
Expand All @@ -44,6 +48,7 @@ def fetch_raw(self, server_id: int) -> dict:
serverconf = self.load()
return serverconf[str(server_id)]

# Fetch Functions
def fetch_autorole(self, server_id: int) -> str:
"""Fetches the specified autorole for the server. Returns `None` if not set."""
return self.fetch_raw(server_id)["autorole"]
Expand All @@ -63,7 +68,15 @@ def fetch_levelup_override_channel(self, server_id: int) -> str:
def fetch_verification_role(self, server_id: int) -> str:
"""Fetches the verified member role for the specified guild. Returns `None` if server verification system is disabled."""
return self.fetch_raw(server_id)["verification_role"]

def fetch_autoresponder_configuration(self, server_id: int, *, autoresponder_name: str = None) -> dict:
"""Fetches a `dict` of the current configuration for autoresponders for the specified guild. Returns an empty `dict` if none are set up."""
if autoresponder_name is not None:
return self.fetch_raw(server_id)["autoresponder"][autoresponder_name]
else:
return self.fetch_raw(server_id)["autoresponder"]

# Set Functions
def set_autorole(self, server_id: int, role_id: int) -> int:
"""Sets a role id to use as autorole for the specified guild. Returns `0` if successful."""
serverconf = self.load()
Expand Down Expand Up @@ -95,3 +108,40 @@ def set_verification_role(self, server_id: int, role_id: int) -> int:
serverconf = self.load()
serverconf[str(server_id)]["verification_role"] = role_id
self.save(serverconf)

# Autoresponder System Functions
def add_autoresponder(
self,
server_id: Union[int, str],
autoresponder_name: str,
autoresponder_trigger: str,
autoresponder_text: str,
autoresponder_trigger_condition: str = Literal["MATCH_MESSAGE", "WITHIN_MESSAGE"],
*,
channel: list = None,
match_case: bool = False
):
"""Adds a new autoresponder configuration for the specified guild, with the provided configuration data. Returns `0` if successful, returns `1` if configuration with same name already exists.\n\nNotes: \n- `autoreponder_name` can be considered as autoresponder id."""
serverconf = self.load()
if autoresponder_name not in serverconf[str(server_id)]["autoresponder"].keys():
serverconf[str(server_id)]["autoresponder"][autoresponder_name] = {
"autoresponder_trigger": autoresponder_trigger,
"autoresponder_text": autoresponder_text,
"autoresponder_trigger_condition": autoresponder_trigger_condition,
"active_channel": channel,
"match_case": match_case
}
self.save(serverconf)
return 0
else: return 1

def remove_autoresponder(self, server_id: Union[int, str], autoresponder_name: str):
"""Removes an existing autoresponder from the specified guild's serverconfig data. Returns `0` if successful, returns `1` if autoresponder does not exist, returns `2` if no autoresponders set up."""
serverconf: dict = self.load()
if autoresponder_name in serverconf[str(server_id)]["autoresponder"].keys():
del serverconf[str(server_id)]["autoresponder"][autoresponder_name]
self.save(serverconf)
else:
if serverconf[str(server_id)]["autoresponder"].keys() == []:
return 2
else: return 1
20 changes: 20 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,26 @@ async def on_message(ctx):
# In that case isobot will automatically stop sending levelup messages to them
logger.warn(f"Unable to send level up message to {ctx.author} ({ctx.author.id}), as they are not accepting DMs from isobot. This ID has been added to `levelup_messages` blacklist.", module="main/Levelling")
settings.edit_setting(ctx.author.id, "levelup_messages", False)

# Autoresponder System
server_autoresponder_config: dict = serverconfig.fetch_autoresponder_configuration(ctx.guild.id)

for config in server_autoresponder_config.keys():
if server_autoresponder_config[config]["active_channel"] == None or server_autoresponder_config[config]["active_channel"] == ctx.channel.id:
if server_autoresponder_config[config]["match_case"]:
if server_autoresponder_config[config]["autoresponder_trigger_condition"] == "MATCH_MESSAGE":
if ctx.content == server_autoresponder_config[config]["autoresponder_trigger"]:
await ctx.channel.send(server_autoresponder_config[config]["autoresponder_text"])
elif server_autoresponder_config[config]["autoresponder_trigger_condition"] == "WITHIN_MESSAGE":
if server_autoresponder_config[config]["autoresponder_trigger"] in ctx.content:
await ctx.channel.send(server_autoresponder_config[config]["autoresponder_text"])
else:
if server_autoresponder_config[config]["autoresponder_trigger_condition"] == "MATCH_MESSAGE":
if ctx.content.lower() == server_autoresponder_config[config]["autoresponder_trigger"]:
await ctx.channel.send(server_autoresponder_config[config]["autoresponder_text"])
elif server_autoresponder_config[config]["autoresponder_trigger_condition"] == "WITHIN_MESSAGE":
if server_autoresponder_config[config]["autoresponder_trigger"] in ctx.content.lower():
await ctx.channel.send(server_autoresponder_config[config]["autoresponder_text"])

# Error handler
@client.event
Expand Down