From e0427d19e64504c640296fe4d8c35aa1e455cbaf Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Fri, 5 Jun 2026 15:31:42 -0700 Subject: [PATCH 1/3] Add a rule command to modmail --- techsupport_bot/commands/__init__.py | 1 + techsupport_bot/commands/modmail.py | 33 +++++++ techsupport_bot/commands/rules.py | 128 ++++++++++++++------------- 3 files changed, 100 insertions(+), 62 deletions(-) diff --git a/techsupport_bot/commands/__init__.py b/techsupport_bot/commands/__init__.py index 720c19524..f35e80813 100644 --- a/techsupport_bot/commands/__init__.py +++ b/techsupport_bot/commands/__init__.py @@ -22,4 +22,5 @@ from .notes import * from .relay import * from .roll import * +from .rules import * from .wyr import * diff --git a/techsupport_bot/commands/modmail.py b/techsupport_bot/commands/modmail.py index 027a9e9dd..a175d1424 100644 --- a/techsupport_bot/commands/modmail.py +++ b/techsupport_bot/commands/modmail.py @@ -22,6 +22,7 @@ import expiringdict import munch import ui +from commands import rules from core import auxiliary, cogs, extensionconfig from discord.ext import commands @@ -1131,6 +1132,37 @@ async def on_message(self: Self, message: discord.Message) -> None: anonymous=True, ) + case "rule": + if "rules" not in config.enabled_extensions: + await auxiliary.send_deny_embed( + message="Rules are not enabled in this guild", + channel=message.channel, + ) + return + rule_num = int(content[4:]) + + raw_rules = await rules.get_guild_rules(self.bot, message.guild) + guild_rules = raw_rules.get("rules") + + try: + rule = guild_rules[rule_num - 1] + except IndexError: + await auxiliary.send_deny_embed( + message=f"Couldn't find the rule `{rule_num}`", + channel=message.channel, + ) + return + + await reply_to_thread( + raw_contents=str( + f"## Rule {rule_num}: {rule.get('name', 'None')}" + f"\n{rule.get('description', 'None')}" + ), + message=message, + thread=message.channel, + anonymous=True, + ) + # Checks if the command was an alias aliases = config.extensions.modmail.aliases.value @@ -1303,6 +1335,7 @@ def modmail_commands_list(self: Self) -> list[tuple[str, str, str, str]]: (prefix, "reply", "[message]", "Sends a message"), (prefix, "areply", "[message]", "Sends a message anonymously"), (prefix, "send", "[factoid]", "Sends the user a factoid"), + (prefix, "rule", "[rule_num]", "Sends the user a rule"), ( prefix, "close", diff --git a/techsupport_bot/commands/rules.py b/techsupport_bot/commands/rules.py index 962535618..a2447236f 100644 --- a/techsupport_bot/commands/rules.py +++ b/techsupport_bot/commands/rules.py @@ -46,63 +46,6 @@ async def rule_group(self: Self, ctx: commands.Context) -> None: """ return - async def get_guild_rules(self: Self, guild: discord.Guild) -> munch.Munch: - """Gets the munchified rules for a given guild. - Will create and write to the database if no rules exist - - Args: - guild (discord.Guild): The guild to get rules for - - Returns: - munch.Munch: The munchified rules ready to be parsed and shown to the user - """ - query = await self.bot.models.Rule.query.where( - self.bot.models.Rule.guild_id == str(guild.id) - ).gino.first() - if not query: - # Handle case where guild doesn't have rules - rules_data = json.dumps( - { - "rules": [ - { - "name": "Anti-Spam", - "description": "No spamming! (this is an example rule)", - }, - { - "name": "No Harassment", - "description": "Keep it friendly! (this is an example rule)", - }, - ], - } - ) - new_rules = munch.munchify(json.loads(rules_data)) - await self.write_new_rules(guild=guild, rules=new_rules) - return munch.munchify(json.loads(rules_data)) - return munch.munchify(json.loads(query.rules)) - - async def write_new_rules( - self: Self, guild: discord.Guild, rules: munch.Munch - ) -> None: - """This converts the munchified rules into a string and writes it to the database - - Args: - guild (discord.Guild): The guild to write the rules for - rules (munch.Munch): The rules to convert and write - """ - query = await self.bot.models.Rule.query.where( - self.bot.models.Rule.guild_id == str(guild.id) - ).gino.first() - if not query: - # Handle case where guild doesn't have rules - rules_data = json.dumps(rules) - new_guild_rules = self.bot.models.Rule( - guild_id=str(guild.id), - rules=str(json.dumps(rules_data)), - ) - await new_guild_rules.create() - else: - await query.update(rules=str(json.dumps(rules))).apply() - @commands.has_permissions(administrator=True) @commands.guild_only() @rule_group.command( @@ -121,13 +64,13 @@ async def edit_rules(self: Self, ctx: commands.Context) -> None: uploaded_data = await auxiliary.get_json_from_attachments(ctx.message) if uploaded_data: uploaded_data["guild_id"] = str(ctx.guild.id) - await self.write_new_rules(ctx.guild, uploaded_data) + await write_new_rules(self.bot, ctx.guild, uploaded_data) await auxiliary.send_confirm_embed( message="I've updated to those rules", channel=ctx.channel ) return - rules_data = await self.get_guild_rules(ctx.guild) + rules_data = await get_guild_rules(self.bot, ctx.guild) json_file = discord.File( io.StringIO(json.dumps(rules_data, indent=4)), @@ -182,7 +125,7 @@ async def get_rule(self: Self, ctx: commands.Context, content: str) -> None: color=discord.Color.gold(), url=self.RULE_ICON_URL, ) - raw_rules = await self.get_guild_rules(ctx.guild) + raw_rules = await get_guild_rules(self.bot, ctx.guild) guild_rules = raw_rules.get("rules") for rule_number in numbers: embed.add_field( @@ -209,7 +152,7 @@ async def get_all_rules(self: Self, ctx: commands.Context) -> None: Args: ctx (commands.Context): The context that was generated when the command was run """ - rules_data = await self.get_guild_rules(ctx.guild) + rules_data = await get_guild_rules(self.bot, ctx.guild) if not rules_data or not rules_data.get("rules"): await auxiliary.send_confirm_embed( message="There are no rules for this server", channel=ctx.channel @@ -244,8 +187,69 @@ async def get_rule_count(self: Self, guild: discord.Guild) -> int: Returns: int: The number of rules in the given guild """ - rules_data = await self.get_guild_rules(guild) + rules_data = await get_guild_rules(self.bot, guild) if not rules_data or not rules_data.get("rules"): return 0 return len(rules_data.get("rules")) + + +async def get_guild_rules(bot: object, guild: discord.Guild) -> munch.Munch: + """Gets the munchified rules for a given guild. + Will create and write to the database if no rules exist + + Args: + bot (object): The instance of TS to use + guild (discord.Guild): The guild to get rules for + + Returns: + munch.Munch: The munchified rules ready to be parsed and shown to the user + """ + query = await bot.models.Rule.query.where( + bot.models.Rule.guild_id == str(guild.id) + ).gino.first() + if not query: + # Handle case where guild doesn't have rules + rules_data = json.dumps( + { + "rules": [ + { + "name": "Anti-Spam", + "description": "No spamming! (this is an example rule)", + }, + { + "name": "No Harassment", + "description": "Keep it friendly! (this is an example rule)", + }, + ], + } + ) + new_rules = munch.munchify(json.loads(rules_data)) + await write_new_rules(guild=guild, rules=new_rules) + return munch.munchify(json.loads(rules_data)) + return munch.munchify(json.loads(query.rules)) + + +async def write_new_rules( + bot: object, guild: discord.Guild, rules: munch.Munch +) -> None: + """This converts the munchified rules into a string and writes it to the database + + Args: + bot (object): The instance of TS to use + guild (discord.Guild): The guild to write the rules for + rules (munch.Munch): The rules to convert and write + """ + query = await bot.models.Rule.query.where( + bot.models.Rule.guild_id == str(guild.id) + ).gino.first() + if not query: + # Handle case where guild doesn't have rules + rules_data = json.dumps(rules) + new_guild_rules = bot.models.Rule( + guild_id=str(guild.id), + rules=str(json.dumps(rules_data)), + ) + await new_guild_rules.create() + else: + await query.update(rules=str(json.dumps(rules))).apply() From 9114e143e682d1800a30caee421cb9252d684511 Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Fri, 5 Jun 2026 15:36:12 -0700 Subject: [PATCH 2/3] Fix bug --- techsupport_bot/commands/rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techsupport_bot/commands/rules.py b/techsupport_bot/commands/rules.py index a2447236f..2d9913a1b 100644 --- a/techsupport_bot/commands/rules.py +++ b/techsupport_bot/commands/rules.py @@ -225,7 +225,7 @@ async def get_guild_rules(bot: object, guild: discord.Guild) -> munch.Munch: } ) new_rules = munch.munchify(json.loads(rules_data)) - await write_new_rules(guild=guild, rules=new_rules) + await write_new_rules(bot=bot, guild=guild, rules=new_rules) return munch.munchify(json.loads(rules_data)) return munch.munchify(json.loads(query.rules)) From 83db476cdff7e03846db36c1d5a4d8d573de90ba Mon Sep 17 00:00:00 2001 From: ajax146 <31014239+ajax146@users.noreply.github.com> Date: Sun, 7 Jun 2026 14:32:40 -0700 Subject: [PATCH 3/3] Fix bug --- techsupport_bot/commands/modmail.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/techsupport_bot/commands/modmail.py b/techsupport_bot/commands/modmail.py index 9204af0df..0663bf0bf 100644 --- a/techsupport_bot/commands/modmail.py +++ b/techsupport_bot/commands/modmail.py @@ -1070,7 +1070,9 @@ async def on_message(self: Self, message: discord.Message) -> None: ) case "rule": - if "rules" not in config.enabled_extensions: + if "rules" not in configuration.get_config_entry( + message.guild.id, "core_enabled_extensions" + ): await auxiliary.send_deny_embed( message="Rules are not enabled in this guild", channel=message.channel,