Skip to content

Commit bb82400

Browse files
authored
Merge pull request #391 from PyBotDevs/server-message-autoresponder
Add custom server message autoresponder system to serverconfig
2 parents b64225f + 5e812a3 commit bb82400

File tree

3 files changed

+193
-1
lines changed

3 files changed

+193
-1
lines changed

cogs/serverconfig.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,128 @@ async def verify(self, ctx: ApplicationContext, verification_code: int):
264264
json.dump(self.verification_db, f, indent=4)
265265

266266
return await ctx.respond(f"You have been successfully verified in **{vcode_guild.name}**!")
267+
268+
# Autoresponder Configuration Commands
269+
autoresponder_commands = SlashCommandGroup(name="autoresponder", description="Commands related to the management of server text-based autoresponders.")
270+
271+
@autoresponder_commands.command(
272+
name="autoresponder_add",
273+
description="Add a new text-based autoresponder to your server."
274+
)
275+
@option(name="autoresponder_name", description="The name (id) of the autoresponder.", type=str)
276+
@option(name="text_trigger", description="The text on which the autoresponder is triggered.", type=str)
277+
@option(name="text_response", description="The response you want the bot to send, when triggered.", type=str)
278+
@option(name="trigger_condition", description="How do you want the autoresponder to be triggered?", type=str, choices=["MATCH_MESSAGE", "WITHIN_MESSAGE"])
279+
@option(name="active_channel", description="In which channel do you want the autoresponder to be active?", type=discord.TextChannel, default=None)
280+
@option(name="match_case", description="Do you want the trigger to be case-sensitive?", type=bool, default=False)
281+
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):
282+
"""Add a new text-based autoresponder to your server."""
283+
if not ctx.author.guild_permissions.manage_messages:
284+
return await ctx.respond("You can't use this command! You need the `Manage Messages` permission to run this.", ephemeral=True)
285+
result_code = serverconf.add_autoresponder(
286+
ctx.guild.id,
287+
autoresponder_name=autoresponder_name,
288+
autoresponder_trigger=text_trigger,
289+
autoresponder_text=text_response,
290+
autoresponder_trigger_condition=trigger_condition,
291+
channel=active_channel.id if active_channel is not None else None,
292+
match_case=match_case
293+
)
294+
if result_code == 1:
295+
localembed = discord.Embed(
296+
title=":warning: An Autoresponder Already Exists With This Name",
297+
description="Try again using a different name, or remove the existing autoresponder and run this command again.",
298+
color=discord.Color.orange()
299+
)
300+
return await ctx.respond(embed=localembed)
301+
localembed = discord.Embed(
302+
title=":white_check_mark: Autoresponder Successfully Created",
303+
description=f"Autoresponder Name: `{autoresponder_name}`\n\nYou may use the autoresponder name to reference this autoresponder, for editing or deleting.",
304+
color=discord.Color.green()
305+
)
306+
localembed.add_field(name="Text Trigger", value=text_trigger)
307+
localembed.add_field(name="Bot Response", value=text_response)
308+
localembed.add_field(name="Autoresponder Trigger Condition", value=trigger_condition)
309+
if active_channel == None:
310+
localembed.add_field(name="Active Channel", value="all channels")
311+
else:
312+
localembed.add_field(name="Active Channel", value=f"<#{active_channel.id}>")
313+
localembed.add_field(name="Match Case?", value=match_case)
314+
await ctx.respond(embed=localembed)
315+
316+
@autoresponder_commands.command(
317+
name="autoresponder_remove",
318+
description="Remove an existing autoresponder from your server."
319+
)
320+
@option(name="autoresponder_name", description="The name of the autoresponder you want to remove.", type=str)
321+
async def autoresponder_remove(self, ctx: ApplicationContext, autoresponder_name: str):
322+
"""Remove an existing autoresponder from your server."""
323+
if not ctx.author.guild_permissions.manage_messages:
324+
return await ctx.respond("You can't use this command! You need the `Manage Messages` permission to run this.", ephemeral=True)
325+
result_code = serverconf.remove_autoresponder(ctx.guild.id, autoresponder_name)
326+
if result_code == 1:
327+
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())
328+
return await ctx.respond(embed=localembed)
329+
elif result_code == 2:
330+
localembed = discord.Embed(
331+
title=":grey_question: No Autoresponders Set",
332+
description=f"You don't have any autoresponders you can remove, let alone something with the name `{autoresponder_name}`.",
333+
color=discord.Color.orange()
334+
)
335+
return await ctx.respond(embed=localembed)
336+
localembed = discord.Embed(
337+
title=f":white_check_mark: Autoresponder `{autoresponder_name}` Successfully Removed",
338+
description="The bot will now not respond to this autoresponder's trigger.",
339+
color=discord.Color.green()
340+
)
341+
await ctx.respond(embed=localembed)
342+
343+
@autoresponder_commands.command(
344+
name="autoresponder_list",
345+
description="View a list of all the autoresponders in the server, or info on a specific autoresponder."
346+
)
347+
@option(name="autoresponder_name", description="Which autoresponder do you want to view information about?", type=str, default=None)
348+
async def autoresponder_list(self, ctx: ApplicationContext, autoresponder_name: str = None):
349+
"""View a list of all the autoresponders in the server, or view specific information on an autoresponder."""
350+
if not ctx.author.guild_permissions.manage_messages:
351+
return await ctx.respond("You can't use this command! You need the `Manage Messages` permission to run this.", ephemeral=True)
352+
353+
# For List of All Autoresponders
354+
if autoresponder_name == None:
355+
autoresponders_list = serverconf.fetch_autoresponder_configuration(ctx.guild.id).keys()
356+
if autoresponders_list == []:
357+
localembed = discord.Embed(
358+
title=":grey_question: No Autoresponders Set",
359+
description=f"There are no autoresponders to show here...",
360+
color=discord.Color.orange()
361+
)
362+
return await ctx.respond(embed=localembed)
363+
parsed_output = str()
364+
sr = 0
365+
for key in autoresponders_list:
366+
sr += 1
367+
parsed_output += f"{sr}. `{key}`"
368+
localembed = discord.Embed(title=f"Autoresponders List for **{ctx.guild}**", description=parsed_output, color=discord.Color.random())
369+
localembed.set_footer(text="Run /autoresponder_list <autoresponder_name> to get more information on a specific autoresponder.")
370+
await ctx.respond(embed=localembed)
371+
372+
# For Specific Autoresponder Configuration
373+
else:
374+
if autoresponder_name in serverconf.fetch_autoresponder_configuration(ctx.guild.id).keys():
375+
autoresponder_data: dict = serverconf.fetch_autoresponder_configuration(ctx.guild.id, autoresponder_name=autoresponder_name)
376+
localembed = discord.Embed(title=f"Information on Autoresponder `{autoresponder_name}`")
377+
localembed.add_field(name="Text Trigger", value=autoresponder_data["autoresponder_trigger"])
378+
localembed.add_field(name="Bot Response", value=autoresponder_data["autoresponder_text"])
379+
localembed.add_field(name="Autoresponder Trigger Condition", value=autoresponder_data["autoresponder_trigger_condition"])
380+
if autoresponder_data["active_channel"] == None:
381+
localembed.add_field(name="Active Channel", value="all channels")
382+
else:
383+
localembed.add_field(name="Active Channel", value=f"<#{autoresponder_data['active_channel']}>")
384+
localembed.add_field(name="Match Case?", value=autoresponder_data["match_case"])
385+
await ctx.respond(embed=localembed)
386+
else:
387+
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())
388+
return await ctx.respond(embed=localembed)
267389

268390
def setup(bot):
269391
bot.add_cog(ServerConfig(bot))

framework/isobot/db/serverconfig.py

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
# Imports
44
import json
5+
from typing_extensions import Literal, Union
56
from framework.isobot.colors import Colors as colors
67

78
# Functions
@@ -34,7 +35,10 @@ def generate(self, server_id: int) -> int:
3435
"message": None
3536
},
3637
"level_up_override_channel": None,
37-
"verification_role": None
38+
"verification_role": None,
39+
"autoresponder": {
40+
41+
}
3842
}
3943
self.save(serverconf)
4044
return 0
@@ -44,6 +48,7 @@ def fetch_raw(self, server_id: int) -> dict:
4448
serverconf = self.load()
4549
return serverconf[str(server_id)]
4650

51+
# Fetch Functions
4752
def fetch_autorole(self, server_id: int) -> str:
4853
"""Fetches the specified autorole for the server. Returns `None` if not set."""
4954
return self.fetch_raw(server_id)["autorole"]
@@ -63,7 +68,15 @@ def fetch_levelup_override_channel(self, server_id: int) -> str:
6368
def fetch_verification_role(self, server_id: int) -> str:
6469
"""Fetches the verified member role for the specified guild. Returns `None` if server verification system is disabled."""
6570
return self.fetch_raw(server_id)["verification_role"]
71+
72+
def fetch_autoresponder_configuration(self, server_id: int, *, autoresponder_name: str = None) -> dict:
73+
"""Fetches a `dict` of the current configuration for autoresponders for the specified guild. Returns an empty `dict` if none are set up."""
74+
if autoresponder_name is not None:
75+
return self.fetch_raw(server_id)["autoresponder"][autoresponder_name]
76+
else:
77+
return self.fetch_raw(server_id)["autoresponder"]
6678

79+
# Set Functions
6780
def set_autorole(self, server_id: int, role_id: int) -> int:
6881
"""Sets a role id to use as autorole for the specified guild. Returns `0` if successful."""
6982
serverconf = self.load()
@@ -95,3 +108,40 @@ def set_verification_role(self, server_id: int, role_id: int) -> int:
95108
serverconf = self.load()
96109
serverconf[str(server_id)]["verification_role"] = role_id
97110
self.save(serverconf)
111+
112+
# Autoresponder System Functions
113+
def add_autoresponder(
114+
self,
115+
server_id: Union[int, str],
116+
autoresponder_name: str,
117+
autoresponder_trigger: str,
118+
autoresponder_text: str,
119+
autoresponder_trigger_condition: str = Literal["MATCH_MESSAGE", "WITHIN_MESSAGE"],
120+
*,
121+
channel: list = None,
122+
match_case: bool = False
123+
):
124+
"""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."""
125+
serverconf = self.load()
126+
if autoresponder_name not in serverconf[str(server_id)]["autoresponder"].keys():
127+
serverconf[str(server_id)]["autoresponder"][autoresponder_name] = {
128+
"autoresponder_trigger": autoresponder_trigger,
129+
"autoresponder_text": autoresponder_text,
130+
"autoresponder_trigger_condition": autoresponder_trigger_condition,
131+
"active_channel": channel,
132+
"match_case": match_case
133+
}
134+
self.save(serverconf)
135+
return 0
136+
else: return 1
137+
138+
def remove_autoresponder(self, server_id: Union[int, str], autoresponder_name: str):
139+
"""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."""
140+
serverconf: dict = self.load()
141+
if autoresponder_name in serverconf[str(server_id)]["autoresponder"].keys():
142+
del serverconf[str(server_id)]["autoresponder"][autoresponder_name]
143+
self.save(serverconf)
144+
else:
145+
if serverconf[str(server_id)]["autoresponder"].keys() == []:
146+
return 2
147+
else: return 1

main.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,26 @@ async def on_message(ctx):
307307
# In that case isobot will automatically stop sending levelup messages to them
308308
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")
309309
settings.edit_setting(ctx.author.id, "levelup_messages", False)
310+
311+
# Autoresponder System
312+
server_autoresponder_config: dict = serverconfig.fetch_autoresponder_configuration(ctx.guild.id)
313+
314+
for config in server_autoresponder_config.keys():
315+
if server_autoresponder_config[config]["active_channel"] == None or server_autoresponder_config[config]["active_channel"] == ctx.channel.id:
316+
if server_autoresponder_config[config]["match_case"]:
317+
if server_autoresponder_config[config]["autoresponder_trigger_condition"] == "MATCH_MESSAGE":
318+
if ctx.content == server_autoresponder_config[config]["autoresponder_trigger"]:
319+
await ctx.channel.send(server_autoresponder_config[config]["autoresponder_text"])
320+
elif server_autoresponder_config[config]["autoresponder_trigger_condition"] == "WITHIN_MESSAGE":
321+
if server_autoresponder_config[config]["autoresponder_trigger"] in ctx.content:
322+
await ctx.channel.send(server_autoresponder_config[config]["autoresponder_text"])
323+
else:
324+
if server_autoresponder_config[config]["autoresponder_trigger_condition"] == "MATCH_MESSAGE":
325+
if ctx.content.lower() == server_autoresponder_config[config]["autoresponder_trigger"]:
326+
await ctx.channel.send(server_autoresponder_config[config]["autoresponder_text"])
327+
elif server_autoresponder_config[config]["autoresponder_trigger_condition"] == "WITHIN_MESSAGE":
328+
if server_autoresponder_config[config]["autoresponder_trigger"] in ctx.content.lower():
329+
await ctx.channel.send(server_autoresponder_config[config]["autoresponder_text"])
310330

311331
# Error handler
312332
@client.event

0 commit comments

Comments
 (0)