From a0bcd42f2fc045856bfd0b0ebfc95c5b94bd00b4 Mon Sep 17 00:00:00 2001 From: Yiays Date: Thu, 24 Jul 2025 15:47:36 +1200 Subject: [PATCH 1/7] Added flags to languages to support a new upstream feature --- babel/confessionbot_de.ini | 1 + babel/confessionbot_en.ini | 1 + babel/confessionbot_fr.ini | 1 + babel/confessionbot_pl.ini | 1 + babel/confessionbot_pt-BR.ini | 1 + babel/confessionbot_tl.ini | 1 + babel/confessionbot_vn.ini | 1 + babel/confessionbot_zh.ini | 1 + 8 files changed, 8 insertions(+) diff --git a/babel/confessionbot_de.ini b/babel/confessionbot_de.ini index 75e83a7..ff17fd3 100755 --- a/babel/confessionbot_de.ini +++ b/babel/confessionbot_de.ini @@ -1,6 +1,7 @@ [meta] name = German (Germany) language = confessionbot_de +flag = 🇩🇪 contributors = 3n3scan#6908 inherit = de diff --git a/babel/confessionbot_en.ini b/babel/confessionbot_en.ini index f658693..d4b7a65 100755 --- a/babel/confessionbot_en.ini +++ b/babel/confessionbot_en.ini @@ -1,6 +1,7 @@ [meta] name = English language = confessionbot_en +flag = 🇬🇧 contributors = Yiays#5930 inherit = en diff --git a/babel/confessionbot_fr.ini b/babel/confessionbot_fr.ini index 7477523..59c3001 100755 --- a/babel/confessionbot_fr.ini +++ b/babel/confessionbot_fr.ini @@ -1,6 +1,7 @@ [meta] name = French (France) language = confessionbot_fr +flag = 🇫🇷 contributors = charabe inherit = fr diff --git a/babel/confessionbot_pl.ini b/babel/confessionbot_pl.ini index 986aa0b..a9ace2c 100755 --- a/babel/confessionbot_pl.ini +++ b/babel/confessionbot_pl.ini @@ -1,6 +1,7 @@ [meta] name = Polish (Poland) language = confessionbot_pl +flag = 🇵🇱 contributors = stethoscope#1538 inherit = pl diff --git a/babel/confessionbot_pt-BR.ini b/babel/confessionbot_pt-BR.ini index d62b528..ce34d17 100755 --- a/babel/confessionbot_pt-BR.ini +++ b/babel/confessionbot_pt-BR.ini @@ -1,6 +1,7 @@ [meta] name = Português (Brasil) language = confessionbot_pt-BR +flag = 🇧🇷 contributors = kob#2618, Windows inherit = pt-BR diff --git a/babel/confessionbot_tl.ini b/babel/confessionbot_tl.ini index 86ebee4..82ca117 100755 --- a/babel/confessionbot_tl.ini +++ b/babel/confessionbot_tl.ini @@ -1,6 +1,7 @@ [meta] name = Tagalog (Philippines) language = confessionbot_tl +flag = 🇵🇭 contributors = Jëssä ♡#1993 and ChoccyMilk#7464 inherit = tl diff --git a/babel/confessionbot_vn.ini b/babel/confessionbot_vn.ini index 618fb76..2ccceaa 100644 --- a/babel/confessionbot_vn.ini +++ b/babel/confessionbot_vn.ini @@ -1,6 +1,7 @@ [meta] name = Tiếng Việt language = confessionbot_vn +flag = 🇻🇳 contributors = y4neko inherit = vn diff --git a/babel/confessionbot_zh.ini b/babel/confessionbot_zh.ini index 0120f80..89f25b5 100755 --- a/babel/confessionbot_zh.ini +++ b/babel/confessionbot_zh.ini @@ -1,6 +1,7 @@ [meta] name = 中文(繁體) language = confessionbot_zh +flag = 🇭🇰 contributors = 女神_a#3330 inherit = zh From c40911c7565d487cbd17c5481a6dc95a016c15f5 Mon Sep 17 00:00:00 2001 From: Yiays Date: Thu, 24 Jul 2025 16:58:53 +1200 Subject: [PATCH 2/7] Add translation support to all commands --- babel/confessionbot_en.ini | 29 ++++++++++++++++++++++++++- extensions/confessions.py | 26 +++++++++++++++--------- extensions/confessions_marketplace.py | 15 ++++++++------ extensions/confessions_moderation.py | 13 +++++++----- extensions/confessions_setup.py | 10 +++++++-- 5 files changed, 69 insertions(+), 24 deletions(-) diff --git a/babel/confessionbot_en.ini b/babel/confessionbot_en.ini index d4b7a65..4dd1919 100755 --- a/babel/confessionbot_en.ini +++ b/babel/confessionbot_en.ini @@ -34,21 +34,47 @@ feature_2_desc = **Add a branding message above every confession** - You could m feature_custom_desc = **DM Confessions and custom features available** - Get in touch with {c:main/creator} in the (support server)[{c:help/serverinv}] about your custom requirements. *This requires a more expensive tier of support*. [confessions] +command_Confession_Reply = Confession Reply +command_Confession_Report = Confession Report +command_confess = confess +command_confess_desc = Send an anonymous message to this channel. +command_confess_content_desc = The text of your anonymous message, leave blank for a paragraph editor. +command_confess_image_desc = An optional image that can appear below or instead of text. command_confess_help = {p:{cmd}} [message] [image] Write an anonymous message to send in this channel. Only works if the channel is set. {p:confess} without any options set will open a paragraph editor. Only images are supported. Videos (and any other files) will not send. +command_confess-to = confess-to +command_confess-to_desc = Send an anonymous message to a specific channel. +command_confess-to_channel_desc = The channel you would like to send to. Including channels you can't see. command_confess-to_help = {p:{cmd}} (channel) [message] [image] Write an anonymous message to send in any channel on this server. Autocomplete will list all channels that you can use. Refer to {p:help} confess for how to write a confession. +command_setup = setup +command_setup_desc = Manage anonymous channels and their settings command_setup_help = {p:{cmd}} Opens an interactive panel where you can setup confessions channels and change settings for each channel. +command_list = list +command_list_desc = List all anonymous channels available here. command_list_help = {p:{cmd}} Lists all currently available anonymous channels on this server. +command_block = block +command_block_desc = Block or unblock any specified anon-ID from confessing on this server. +command_block_anonid_desc = The Anon-ID found next to a traceable anonymous message +command_block_unblock_desc = Unblocks the Anon-ID when this is set to true command_block_help = {p:{cmd}} (anon-id) [unblock] Block any anon-id from sending anonymous messages. Blocks last until the next time you shuffle ids. - Unblock by setting unblock to false; {p:block} abc123 true + Unblock by setting unblock to true. Eg. {p:block} anonid=abc123 unblock=true +command_shuffle = shuffle +command_shuffle_desc = Ramdomize all anon-IDs on this server to protect anonymity command_shuffle_help = {p:{cmd}} Resets all anon-ids to reduce the chances of one user being tracked and identified. +command_sell = sell +command_sell_desc = List an item you would like to sell anonymously +command_sell_title_desc = Describe what you are selling in a few words +command_sell_starting_price_desc = A target price you would likely accept, include the currency +command_sell_payment_methods_desc = List ways you would accept payment. Eg. PayPal, Venmo, Crypto +command_sell_description_desc = Describe what you are selling in depth, use /confess to add more later +command_sell_image_desc = An image of the item, if that is applicable command_sell_help = {p:{cmd}} (title) (starting_price) (payment_methods) [description] [image] Create a listing for an item you intend on selling. Listings can only be in maretplace channels - use {p:list} to find one. Listings are anonymous, however, once you accept a price offer from a buyer, you share usernames with each other. @@ -92,6 +118,7 @@ no_moderation = Moderation features have been disabled on this bot, so this isn' cachebuilding = {c:main/botname} is still starting up, channel lists in DMs might be incomplete during this time. > *{p:confess}, {p:confess-to}, and {p:list} all work without any wait times on servers.* vetting = **Some of these channels have vetting enabled.** A mod on the server may need to approve or deny your confession before it is posted publicly. You will still remain anonymous throughout the process. +concat_list = This list is incomplete, use /list to see all ; confessions channelprompt = Select a destination channel for your anonymous message. channelprompt_pager = Page {page} diff --git a/extensions/confessions.py b/extensions/confessions.py index 8f1c435..0e287ff 100755 --- a/extensions/confessions.py +++ b/extensions/confessions.py @@ -72,7 +72,7 @@ def __init__(self, bot:MerelyBot): self.confession_cooldown = dict() self.confess_reply = app_commands.ContextMenu( - name="Confession Reply", + name=app_commands.locale_str('command_Confession_Reply', scope=self.SCOPE), allowed_contexts=app_commands.AppCommandContext(guild=True, private_channel=False), allowed_installs=app_commands.AppInstallationType(guild=True, user=False), callback=self.confess_reply_callback @@ -80,7 +80,7 @@ def __init__(self, bot:MerelyBot): bot.tree.add_command(self.confess_reply) async def cog_unload(self): - self.bot.tree.remove_command(self.confess_reply.name, type=self.confess_reply.type) + self.bot.tree.remove_command(self.confess_reply.qualified_name, type=self.confess_reply.type) # Context menu commands @@ -280,11 +280,14 @@ async def confession_request(self, msg:discord.Message): # Slash commands - @app_commands.command() + @app_commands.command( + name=app_commands.locale_str('command_confess', scope=SCOPE), + description=app_commands.locale_str('command_confess_desc', scope=SCOPE) + ) @app_commands.allowed_contexts(guilds=True) @app_commands.describe( - content="The text of your anonymous message, leave blank for a paragraph editor", - image="An optional image that appears below the text" + content=app_commands.locale_str('command_confess_content_desc', scope=SCOPE), + image=app_commands.locale_str('command_confess_image_desc', scope=SCOPE) ) @commands.cooldown(1, 1, type=commands.BucketType.user) async def confess( @@ -307,9 +310,9 @@ async def confess( @app_commands.command(name='confess-to') @app_commands.allowed_contexts(guilds=True) @app_commands.describe( - channel="The target channel, can include anonymous feedback channels that you can't see", - content="The text of your anonymous message, leave blank for a paragraph editor", - image="An optional image that appears below the text" + channel=app_commands.locale_str('command_confess-to_channel_desc', scope=SCOPE), + content=app_commands.locale_str('command_confess_content_desc', scope=SCOPE), + image=app_commands.locale_str('command_confess_image_desc', scope=SCOPE) ) @commands.cooldown(1, 1, type=commands.BucketType.user) async def confess_to( @@ -351,11 +354,14 @@ async def channel_ac(self, inter:discord.Interaction, search:str): app_commands.Choice(name=f"{match[1].icon} #{match[0].name}", value=str(match[0].id)) ) return results[0:24] + ( - [app_commands.Choice(name='this list is incomplete, use /list to see all', value='0')] + [app_commands.Choice(name=self.babel(inter, 'concat_list'), value='0')] if len(results) > 25 else [] ) - @app_commands.command() + @app_commands.command( + name=app_commands.locale_str('command_list', scope=SCOPE), + description=app_commands.locale_str('command_list_desc', scope=SCOPE) + ) async def list(self, inter:discord.Interaction): """ List all anonymous channels available here diff --git a/extensions/confessions_marketplace.py b/extensions/confessions_marketplace.py index ec7cd18..1162da1 100644 --- a/extensions/confessions_marketplace.py +++ b/extensions/confessions_marketplace.py @@ -234,14 +234,17 @@ async def on_withdraw(self, inter:discord.Interaction): # Slash commands - @app_commands.command() + @app_commands.command( + name=app_commands.locale_str('command_sell', scope=SCOPE), + description=app_commands.locale_str('command_sell_desc', scope=SCOPE) + ) @app_commands.allowed_contexts(guilds=True) @app_commands.describe( - title="A short summary of the item you are selling", - starting_price="The price you would like to start bidding at, in whatever currency you accept", - payment_methods="Payment methods you will accept, PayPal, Venmo, Crypto, etc.", - description="Further details about the item you are selling", - image="A picture of the item you are selling" + title=app_commands.locale_str('command_sell_title_desc', scope=SCOPE), + starting_price=app_commands.locale_str('command_sell_starting_price_desc', scope=SCOPE), + payment_methods=app_commands.locale_str('command_sell_payment_methods_desc', scope=SCOPE), + description=app_commands.locale_str('command_sell_description_desc', scope=SCOPE), + image=app_commands.locale_str('command_sell_image_desc', scope=SCOPE) ) @commands.cooldown(1, 1, type=commands.BucketType.user) async def sell( diff --git a/extensions/confessions_moderation.py b/extensions/confessions_moderation.py index d00d8b8..5ae5ae2 100644 --- a/extensions/confessions_moderation.py +++ b/extensions/confessions_moderation.py @@ -53,7 +53,7 @@ def __init__(self, bot:MerelyBot): raise Exception("Module `confessions` must be enabled!") self.report = app_commands.ContextMenu( - name="Report confession", + name=app_commands.locale_str('command_Confession_Report', scope=self.SCOPE), allowed_contexts=app_commands.AppCommandContext(guild=True, private_channel=False), allowed_installs=app_commands.AppInstallationType(guild=True, user=False), callback=self.report_callback @@ -61,7 +61,7 @@ def __init__(self, bot:MerelyBot): bot.tree.add_command(self.report) def cog_unload(self): - self.bot.tree.remove_command(self.report.name, type=self.report.type) + self.bot.tree.remove_command(self.report.qualified_name, type=self.report.type) # Context menu commands @@ -334,10 +334,13 @@ async def on_confession_review(self, inter:discord.Interaction): # Commands - @app_commands.command() + @app_commands.command( + name=app_commands.locale_str('command_block', scope=SCOPE), + description=app_commands.locale_str('command_block_desc', scope=SCOPE) + ) @app_commands.describe( - anonid="The anonymous id found next to any traceable anonymous message", - unblock="Set to true if you want to unblock this id instead" + anonid=app_commands.locale_str('command_block_anonid_desc', scope=SCOPE), + unblock=app_commands.locale_str('command_block_unblock_desc', scope=SCOPE) ) @app_commands.allowed_contexts(guilds=True, private_channels=False) @app_commands.default_permissions(moderate_members=True) diff --git a/extensions/confessions_setup.py b/extensions/confessions_setup.py index b257e9a..032c8e7 100644 --- a/extensions/confessions_setup.py +++ b/extensions/confessions_setup.py @@ -365,7 +365,10 @@ async def channel_cleanup(self, channel:discord.TextChannel): # Commands - @app_commands.command() + @app_commands.command( + name=app_commands.locale_str('command_setup', scope=SCOPE), + description=app_commands.locale_str('command_setup_desc', scope=SCOPE) + ) @app_commands.allowed_contexts(guilds=True) @app_commands.default_permissions(manage_channels=True) @commands.bot_has_permissions(read_messages=True) @@ -378,7 +381,10 @@ async def setup(self, inter:discord.Interaction): self.babel(inter, 'setup_start'), view=self.SetupView(inter, self, channel), ephemeral=True ) - @app_commands.command() + @app_commands.command( + name=app_commands.locale_str('command_shuffle', scope=SCOPE), + description=app_commands.locale_str('command_shuffle_desc', scope=SCOPE) + ) @app_commands.allowed_contexts(guilds=True) @app_commands.default_permissions(moderate_members=True) async def shuffle(self, inter:discord.Interaction): From 627346db7165613ef48a943cd60a5238ffd28d2c Mon Sep 17 00:00:00 2001 From: Yiays Date: Thu, 24 Jul 2025 22:46:10 +1200 Subject: [PATCH 3/7] Rewrite bot to support threads alongside channels --- extensions/confessions.py | 73 +++++++++++++----- extensions/confessions_common.py | 103 +++++++++++++++----------- extensions/confessions_marketplace.py | 11 +-- extensions/confessions_moderation.py | 16 ++-- extensions/confessions_setup.py | 19 +++-- 5 files changed, 135 insertions(+), 87 deletions(-) diff --git a/extensions/confessions.py b/extensions/confessions.py index 0e287ff..87d51eb 100755 --- a/extensions/confessions.py +++ b/extensions/confessions.py @@ -21,8 +21,8 @@ from configparser import SectionProxy from overlay.extensions.confessions_common import ( - ChannelType, ChannelSelectView, ConfessionData, NoMemberCacheError, Crypto, get_guildchannels, - safe_fetch_channel + Confessable, ChannelType, ChannelSelectView, ConfessionData, NoMemberCacheError, Crypto, + get_guildchannels, safe_fetch_target ) @@ -91,7 +91,7 @@ async def confess_reply_callback(self, inter:discord.Interaction, message:discor await inter.response.send_message(self.babel(inter, 'confession_reply_failed'), ephemeral=True) return data = ConfessionData(self) - data.create(author=inter.user, targetchannel=inter.channel, reference=message) + data.create(author=inter.user, target=inter.channel, reference=message) await self.verify_and_send(inter, data) # Utility functions @@ -99,16 +99,18 @@ async def confess_reply_callback(self, inter:discord.Interaction, message:discor def generate_list( self, user:discord.User, - matches:list[tuple[discord.TextChannel, ChannelType]], + matches:list[tuple[Confessable, ChannelType]], vetting:bool ) -> str: """ Returns a formatted list of available confession targets """ targets = [] for match in matches: + guildname = self.bot.utilities.truncate(match[0].guild.name, 40) + indent = 4 if isinstance(match[0], discord.Thread) else 0 targets.append( - f'{match[1].icon} <#{match[0].id}>' + - (' ('+match[0].guild.name+')' if not isinstance(user, discord.Member) else '') + f'{'\u200f\u200f\u200e \u200e' * indent}{match[1].icon} <#{match[0].id}>' + + (' ('+guildname+')' if not isinstance(user, discord.Member) else '') ) vettingwarning = ('\n\n'+self.babel(user, 'vetting') if vetting else '') @@ -116,34 +118,52 @@ def generate_list( def scanguild( self, member:discord.Member - ) -> tuple[list[tuple[discord.TextChannel, ChannelType]], bool]: + ) -> tuple[list[tuple[Confessable, ChannelType]], bool]: """ Scans a guild for any targets that a member can use for confessions """ - matches:list[tuple[discord.TextChannel, ChannelType]] = [] + matches:list[tuple[Confessable, ChannelType]] = [] vetting = False guildchannels = get_guildchannels(self.config, member.guild.id) for channel in member.guild.channels: if channel.id in guildchannels: - if guildchannels[channel.id] == ChannelType.vetting: + channeltype = guildchannels[channel.id] + if channeltype == ChannelType.vetting: vetting = True continue - channel.name = channel.name[:40] + ('...' if len(channel.name) > 40 else '') - channel.guild.name = channel.guild.name[:40]+('...' if len(channel.guild.name) > 40 else '') - if 'feedback' in guildchannels[channel.id].name: - matches.append((channel, guildchannels[channel.id])) + if 'feedback' in channeltype.name: + matches += [(channel, channeltype)] + self.scanchannel(channel, channeltype) continue if channel.permissions_for(member).read_messages: - matches.append((channel, guildchannels[channel.id])) + matches += [(channel, channeltype)] + self.scanchannel(channel, channeltype) continue - matches.sort(key=lambda t: (t[0].category.position if t[0].category else 0, t[0].position)) + def sort(t:tuple[Confessable, ChannelType]): + if isinstance(t[0], discord.TextChannel): + return (t[0].category.position if t[0].category else 0, t[0].position) + elif isinstance(t[0], discord.Thread): + return (t[0].category.position if t[0].category else 0, t[0].parent.position) + raise Exception("Confessable target was not a TextChannel or a Thread!") + matches.sort(key=sort) return matches, vetting + def scanchannel( + self, channel:discord.TextChannel, channeltype:ChannelType + ) -> list[tuple[Confessable, ChannelType]]: + """ Scans a channel for any active threads that can be used for confessions """ + + matches:list[Confessable] = [] + for thread in channel.threads: + if thread.type != discord.ChannelType.public_thread: + continue + matches.append((thread, channeltype)) + + return matches + def listavailablechannels( self, user:Union[discord.User, discord.Member] - ) -> tuple[list[tuple[discord.TextChannel, ChannelType]], bool]: + ) -> tuple[list[tuple[Confessable, ChannelType]], bool]: """ List all available targets on a server for a member List all available targets on all mutual servers for a user @@ -300,7 +320,7 @@ async def confess( Send an anonymous message to this channel """ pendingconfession = ConfessionData(self) - pendingconfession.create(author=inter.user, targetchannel=inter.channel) + pendingconfession.create(author=inter.user, target=inter.channel) pendingconfession.set_content(content) if image: await inter.response.defer(ephemeral=True) @@ -326,9 +346,9 @@ async def confess_to( Send an anonymous message to a specified channel """ if channel.isdigit() and int(channel): - if targetchannel := await safe_fetch_channel(self, inter, int(channel)): + if targetchannel := await safe_fetch_target(self, inter, int(channel)): pendingconfession = ConfessionData(self) - pendingconfession.create(author=inter.user, targetchannel=targetchannel) + pendingconfession.create(author=inter.user, target=targetchannel) pendingconfession.set_content(content) if image: await inter.response.defer(ephemeral=True) @@ -350,8 +370,21 @@ async def channel_ac(self, inter:discord.Interaction, search:str): matches, _ = self.scanguild(inter.user) for match in matches: if search in match[0].name: + name:str + if isinstance(match[0], discord.TextChannel): + name = self.bot.utilities.truncate(match[0].name, 40) + elif isinstance(match[0], discord.Thread): + name = ( + self.bot.utilities.truncate(match[0].parent.name, 20) + '/' + + self.bot.utilities.truncate(match[0].name, 20) + ) + else: + name = 'UNKNOWN TYPE' results.append( - app_commands.Choice(name=f"{match[1].icon} #{match[0].name}", value=str(match[0].id)) + app_commands.Choice( + name=f"{match[1].icon} #{name}", + value=str(match[0].id) + ) ) return results[0:24] + ( [app_commands.Choice(name=self.babel(inter, 'concat_list'), value='0')] diff --git a/extensions/confessions_common.py b/extensions/confessions_common.py index 75a54dc..40191fb 100644 --- a/extensions/confessions_common.py +++ b/extensions/confessions_common.py @@ -23,6 +23,8 @@ from configparser import SectionProxy from babel import Babel, Resolvable +type Confessable = (discord.TextChannel | discord.Thread) + # Data Classes @@ -186,11 +188,11 @@ def set_guildchannels(config:SectionProxy, guild_id:int, guildchannels:dict[int, config.pop(f'{guild_id}_channels') -async def safe_fetch_channel( +async def safe_fetch_target( parent:Confessions | ConfessionsModeration, inter:discord.Interaction, channel_id:int -) -> Optional[discord.TextChannel]: +) -> Optional[Confessable]: """ Gracefully handles whenever a confession target isn't available """ try: return await parent.bot.fetch_channel(channel_id) @@ -217,14 +219,14 @@ class NoMemberCacheError(Exception): class ChannelSelectView(discord.ui.View): """ View for selecting a target interactively """ page: int = 0 - selection: Optional[discord.TextChannel] = None + selection: Optional[Confessable] = None done: bool = False def __init__( self, origin:discord.Message | discord.Interaction, parent:Confessions | ConfessionsSetup, - matches:list[tuple[discord.TextChannel, ChannelType]], + matches:list[tuple[Confessable, ChannelType]], confession:ConfessionData | None = None ): super().__init__() @@ -283,7 +285,9 @@ async def channel_selector(self, inter:discord.Interaction, this:discord.ui.Sele self.update_list() guildchannels = get_guildchannels(self.parent.config, self.selection.guild.id) vetting = findvettingchannel(guildchannels) - channeltype = guildchannels[self.selection.id] + channeltype = guildchannels.get( + self.selection.parent_id if isinstance(self.selection, discord.Thread) else self.selection.id + ) await inter.response.edit_message( content=self.parent.babel( inter, 'channelprompted', channel=self.selection.mention, @@ -302,7 +306,7 @@ async def send_button(self, inter:discord.Interaction, _:discord.Button): if self.confession is None: self.confession = ConfessionData(self.parent) - self.confession.create(author=inter.user, targetchannel=self.selection) + self.confession.create(author=inter.user, target=self.selection) self.confession.set_content(self.origin.content) if self.origin.attachments: @@ -310,7 +314,7 @@ async def send_button(self, inter:discord.Interaction, _:discord.Button): await self.confession.add_image(attachment=self.origin.attachments[0]) else: # Override targetchannel as this has changed - self.confession.create(author=inter.user, targetchannel=self.selection) + self.confession.create(author=inter.user, target=self.selection) if vetting := await self.confession.check_vetting(inter): await self.parent.bot.cogs['ConfessionsModeration'].send_vetting( @@ -463,7 +467,7 @@ class ConfessionData: DATA_VERSION = 2 anonid:str | None author:discord.User - targetchannel:discord.TextChannel + target:Confessable channeltype_flags:int = 0 content:str | None = None reference:discord.Message | discord.PartialMessage | None = None @@ -500,10 +504,13 @@ async def from_binary(self, crypto:Crypto, rawdata:str): else: raise CorruptConfessionDataException("Data format incorrect;", len(binary), "!=", 26) self.author = await self.bot.fetch_user(author_id) - self.targetchannel = await self.bot.fetch_channel(targetchannel_id) - self.anonid = self.get_anonid(self.targetchannel.guild.id, self.author.id) - guildchannels = get_guildchannels(self.config, self.targetchannel.guild.id) - self.channeltype = guildchannels.get(self.targetchannel.id, ChannelType.unset) + self.target = await self.bot.fetch_channel(targetchannel_id) + self.anonid = self.get_anonid(self.target.guild.id, self.author.id) + guildchannels = get_guildchannels(self.config, self.target.guild.id) + self.channeltype = guildchannels.get( + self.target.parent_id if isinstance(self.target, discord.Thread) else self.target.id, + ChannelType.unset + ) self.targetchanneltype = self.channeltype # References must exist in the cache, meaning confession replies will not survive a restart # Note: this assumes the data will only be retreived once @@ -513,19 +520,22 @@ def create( self, *, author:discord.User | None = None, - targetchannel:discord.TextChannel | None = None, + target:Confessable | None = None, reference:discord.Message | None = None ): - if (author and not targetchannel) or (targetchannel and not author): + if (author and not target) or (target and not author): raise Exception("Both author and targetchannel must be provided at the same time") if author: if hasattr(self, 'author') and self.author != author: raise Exception("Attempted to change confession author from", self.author, "to", author, "!") self.author = author - self.targetchannel = targetchannel - self.anonid = self.get_anonid(targetchannel.guild.id, author.id) - guildchannels = get_guildchannels(self.config, targetchannel.guild.id) - self.channeltype = guildchannels.get(targetchannel.id, ChannelType.unset) + self.target = target + self.anonid = self.get_anonid(target.guild.id, author.id) + guildchannels = get_guildchannels(self.config, target.guild.id) + self.channeltype = guildchannels.get( + target.parent_id if isinstance(target, discord.Thread) else target.id, + ChannelType.unset + ) self.targetchanneltype = self.channeltype if reference: self.reference = reference @@ -567,7 +577,7 @@ def store(self) -> str: # Size limit: ~100 bytes bversion = self.DATA_VERSION.to_bytes(1, 'big') bauthor = self.author.id.to_bytes(8, 'big') - btarget = self.targetchannel.id.to_bytes(8, 'big') + btarget = self.target.id.to_bytes(8, 'big') bflags = self.channeltype_flags.to_bytes(1, 'big') if self.reference: breference = self.reference.id.to_bytes(8, 'big') @@ -614,7 +624,7 @@ def generate_embed(self): def check_banned(self) -> bool: """ Verify the user hasn't been banned """ - guild_id = self.targetchannel.guild.id + guild_id = self.target.guild.id if self.anonid in self.config.get(f"{guild_id}_banned", fallback='').split(','): return False return True @@ -622,7 +632,7 @@ def check_banned(self) -> bool: def check_image(self) -> bool: """ Only allow images to be sent if imagesupport is enabled and the image is valid """ image = self.attachment - guild_id = self.targetchannel.guild.id + guild_id = self.target.guild.id if image and image.content_type.startswith('image') and image.size < 25_000_000: # Discord size limit if bool(self.config.get(f"{guild_id}_imagesupport", fallback=True)): @@ -643,13 +653,13 @@ async def check_vetting( ) -> discord.TextChannel | bool | None: """ Check if vetting is required, this is not a part of check_all """ send = (inter.followup.send if inter.response.is_done() else inter.response.send_message) - guildchannels = get_guildchannels(self.config, self.targetchannel.guild.id) + guildchannels = get_guildchannels(self.config, self.target.guild.id) vetting = findvettingchannel(guildchannels) if vetting and self.targetchanneltype.vetted: if 'ConfessionsModeration' not in self.bot.cogs: await send(self.babel(inter, 'no_moderation'), ephemeral=True) return False - return self.targetchannel.guild.get_channel(vetting) + return self.target.guild.get_channel(vetting) return None async def check_all(self, inter:discord.Interaction) -> bool: @@ -671,7 +681,7 @@ async def check_all(self, inter:discord.Interaction) -> bool: # Assume that special_cmd can only be called directly as this is most likely true await send(self.babel( inter, 'wrongcommand', - cmd=self.targetchanneltype.special_cmd, channel=self.targetchannel.mention + cmd=self.targetchanneltype.special_cmd, channel=self.target.mention ), **kwargs) return False else: @@ -711,8 +721,8 @@ async def handle_send_errors(self, inter:discord.Interaction, func): return True except discord.Forbidden: try: - await self.targetchannel.send( - self.babel(self.targetchannel.guild, 'missingperms', perm='Embed Links') + await self.target.send( + self.babel(self.target.guild, 'missingperms', perm='Embed Links') ) await send(self.babel(inter, 'embederr'), **kwargs) except discord.Forbidden: @@ -727,7 +737,7 @@ async def send_confession( success_message:bool = False, perform_checks:bool = True, *, - channel:discord.TextChannel | None = None, + target:Confessable | None = None, webhook_override:bool | None = None, preface_override:str | None = None, **kwargs @@ -748,25 +758,27 @@ async def send_confession( await inter.response.defer(ephemeral=True) # Flag-based behaviour - if channel is None: - channel = self.targetchannel + if target is None: + target = self.target # Update channeltype, in case this channel is different - guildchannels = get_guildchannels(self.config, channel.guild.id) - self.channeltype = guildchannels.get(channel.id, ChannelType.unset) + guildchannels = get_guildchannels(self.config, target.guild.id) + self.channeltype = guildchannels.get( + target.parent_id if isinstance(target, discord.Thread) else target.id, ChannelType.unset + ) if perform_checks: if not await self.check_all(inter): return False preface = ( preface_override if preface_override is not None - else self.config.get(f'{channel.guild.id}_preface', fallback='') + else self.config.get(f'{target.guild.id}_preface', fallback='') ) use_webhook = ( webhook_override if webhook_override is not None - else self.config.getboolean(f'{channel.guild.id}_webhook', False) + else self.config.getboolean(f'{target.guild.id}_webhook', False) ) # Allow external modules to modify the message before sending - if channel == self.targetchannel: + if target == self.target: # ...as long as it's not being intercepted by another mechanism - like vetting if dep := self.channeltype.dep: if dep not in self.bot.cogs: @@ -789,17 +801,19 @@ async def send_confession( # A best effort to always show replies, even if Discord's API doesn't allow for it # Discord does not allow webhooks to reply, disable it use_webhook = False - if self.reference.channel == channel: + if self.reference.channel == target: kwargs['reference'] = discord.MessageReference( - message_id=self.reference.id, channel_id=channel.id, fail_if_not_exists=False + message_id=self.reference.id, channel_id=target.id, fail_if_not_exists=False ) else: # Discord does not allow replies to span multiple channels, reference in plaintext instead - preface += '\n' + self.babel(channel.guild, 'reply_to', reference=self.reference.jump_url) + preface += '\n' + self.babel(target.guild, 'reply_to', reference=self.reference.jump_url) # Send the confession if use_webhook: - if webhook := await self.find_or_create_webhook(channel): + if webhook := await self.find_or_create_webhook(target): + if isinstance(target, discord.Thread): + kwargs['thread'] = target mentions_in_preface = re.findall(r'<[@!&]+\d+>', preface) botcolour = self.bot.config['main']['themecolor'][2:] username = ( @@ -817,30 +831,31 @@ async def send_confession( return False else: self.generate_embed() - func = channel.send(preface, embed=self.embed, **kwargs) + func = target.send(preface, embed=self.embed, **kwargs) success = await self.handle_send_errors(inter, func) - if 'Log' in self.bot.cogs and channel == self.targetchannel: + if 'Log' in self.bot.cogs and target == self.target: logentry = ( - f'{self.targetchannel.guild.name}/{self.anonid} ({self.author.name}): ' + + f'{self.target.guild.name}/{self.anonid} ({self.author.name}): ' + self.bot.utilities.truncate(self.content) + (' (attachment)' if self.file else '') ) await self.bot.cogs['Log'].log_misc_str(content=logentry) # Mark the command as complete by sending a success message if success and success_message: - if inter.channel != self.targetchannel: # confess-to + if inter.channel != self.target: # confess-to await inter.followup.send( - self.babel(inter, 'confession_sent_channel', channel=channel.mention), + self.babel(inter, 'confession_sent_channel', channel=target.mention), ephemeral=True ) else: # confess await inter.followup.send(self.babel(inter, 'confession_sent_below'), ephemeral=True) return success - async def find_or_create_webhook(self, channel:discord.TextChannel) -> discord.Webhook | None: + async def find_or_create_webhook(self, target:Confessable) -> discord.Webhook | None: """ Tries to find a webhook, or create it, or complain about missing permissions """ webhook:discord.Webhook + channel = target.parent if isinstance(target, discord.Thread) else target try: for webhook in await channel.webhooks(): if webhook.user == self.bot.user: diff --git a/extensions/confessions_marketplace.py b/extensions/confessions_marketplace.py index 1162da1..f19fb4b 100644 --- a/extensions/confessions_marketplace.py +++ b/extensions/confessions_marketplace.py @@ -79,10 +79,7 @@ def __init__( async def on_submit(self, inter:discord.Interaction): """ User has completed making their offer """ guildchannels = get_guildchannels(self.parent.config, inter.guild_id) - if ( - inter.channel_id not in guildchannels or - guildchannels[inter.channel_id] != ChannelType.marketplace - ): + if guildchannels.get(inter.channel_id, ChannelType.unset) != ChannelType.marketplace: await inter.response.send_message(self.parent.babel(inter, 'nosendchannel'), ephemeral=True) return @@ -95,7 +92,7 @@ async def on_submit(self, inter:discord.Interaction): pendingconfession = ConfessionData(self.parent.bot.cogs['Confessions']) pendingconfession.create( - author=inter.user, targetchannel=inter.channel, reference=self.origin.message + author=inter.user, target=inter.channel, reference=self.origin.message ) pendingconfession.set_content(embed=embed) pendingconfession.channeltype_flags = MarketplaceFlags.OFFER @@ -276,7 +273,7 @@ async def sell( embed.set_footer(text=self.babel(inter, 'shop_disclaimer')) pendingconfession = ConfessionData(self.bot.cogs['Confessions']) - pendingconfession.create(author=inter.user, targetchannel=inter.channel) + pendingconfession.create(author=inter.user, target=inter.channel) pendingconfession.set_content(embed=embed) if image: await inter.response.defer(ephemeral=True) @@ -303,7 +300,7 @@ async def on_channeltype_send( 'view': self.ListingView(self, inter, id_seller) } elif data.channeltype_flags == MarketplaceFlags.OFFER: - listing = await data.targetchannel.fetch_message(data.reference.id) + listing = await data.target.fetch_message(data.reference.id) id_seller = listing.components[0].children[0].custom_id[28:] raw_buyer = data.parent.crypto.encrypt(data.author.id.to_bytes(8, 'big')) id_buyer = b64encode(raw_buyer).decode('ascii') diff --git a/extensions/confessions_moderation.py b/extensions/confessions_moderation.py index 5ae5ae2..24971ec 100644 --- a/extensions/confessions_moderation.py +++ b/extensions/confessions_moderation.py @@ -19,7 +19,7 @@ from overlay.extensions.confessions_common import Crypto from overlay.extensions.confessions_common import ( - ConfessionData, CorruptConfessionDataException, safe_fetch_channel + ConfessionData, CorruptConfessionDataException, safe_fetch_target ) @@ -104,11 +104,11 @@ async def send_vetting( Send confession to a vetting channel for approval Checks are performed at this stage """ - preface = self.babel(vettingchannel.guild, 'vetmessagecta', channel=data.targetchannel.mention) + preface = self.babel(vettingchannel.guild, 'vetmessagecta', channel=data.target.mention) view = self.PendingConfessionView(self, data) success = await data.send_confession( inter, - channel=vettingchannel, + target=vettingchannel, webhook_override=False, preface_override=preface, view=view @@ -116,7 +116,7 @@ async def send_vetting( if success: await inter.followup.send( - self.babel(inter, 'confession_vetting', channel=data.targetchannel.mention), + self.babel(inter, 'confession_vetting', channel=data.target.mention), ephemeral=True ) @@ -127,7 +127,7 @@ class PendingConfessionView(discord.ui.View): def __init__(self, parent:ConfessionsModeration, pendingconfession:"ConfessionData"): super().__init__(timeout=None) - guild = pendingconfession.targetchannel.guild + guild = pendingconfession.target.guild data = pendingconfession.store() self.add_item(discord.ui.Button( label=parent.babel(guild, 'vetting_approve_button'), @@ -214,7 +214,7 @@ def __init__( async def on_submit(self, inter: discord.Interaction): """ Send report to mod channel as configured """ if self.parent.config['report_channel']: - reportchannel = await safe_fetch_channel( + reportchannel = await safe_fetch_target( self.parent, inter, int(self.parent.config.get('report_channel')) ) if reportchannel is None: @@ -306,7 +306,7 @@ async def on_confession_review(self, inter:discord.Interaction): self.button_lock.remove(custom_id) raise e - metadata = {'user':inter.user.mention, 'channel':pendingconfession.targetchannel.mention} + metadata = {'user':inter.user.mention, 'channel':pendingconfession.target.mention} if accepted: msg = self.babel(inter.guild, 'vetaccepted', **metadata) else: @@ -322,7 +322,7 @@ async def on_confession_review(self, inter:discord.Interaction): content = self.babel( pendingconfession.author, 'confession_vetting_accepted' if accepted else 'confession_vetting_denied', - channel=f"<#{pendingconfession.targetchannel.id}>" + channel=f"<#{pendingconfession.target.id}>" ) if str(pendingconfession.author.id) not in self.config.get('dm_notifications', '').split(','): try: diff --git a/extensions/confessions_setup.py b/extensions/confessions_setup.py index 032c8e7..8641880 100644 --- a/extensions/confessions_setup.py +++ b/extensions/confessions_setup.py @@ -18,9 +18,10 @@ from configparser import SectionProxy from extensions.controlpanel import Toggleable, Stringable, Listable -from overlay.extensions.confessions_common import \ - ChannelType, ChannelSelectView, get_channeltypes, findvettingchannel, get_guildchannels,\ - set_guildchannels +from overlay.extensions.confessions_common import ( + Confessable, ChannelType, ChannelSelectView, get_channeltypes, findvettingchannel, + get_guildchannels, set_guildchannels +) class ConfessionsSetup(commands.Cog): @@ -72,14 +73,14 @@ def controlpanel_theme(self) -> tuple[str, discord.ButtonStyle]: class SetupView(ChannelSelectView): """ Configure channels and shortcuts to configure guild settings """ - current_channel: discord.TextChannel + current_channel: Confessable current_mode: ChannelType def __init__( self, inter:discord.Interaction, parent:ConfessionsSetup, - channel:discord.TextChannel + channel:Confessable ): """ A SetupView extends upon ChannelSelectView @@ -112,14 +113,16 @@ def __init__( linkbutton.callback = self.controlpanel_shortcut self.add_item(linkbutton) - self.current_channel = channel + self.current_channel = channel.parent if isinstance(channel, discord.Thread) else channel guildchannels = get_guildchannels(parent.config, inter.guild.id) - self.current_mode = guildchannels.get(channel.id, ChannelType.unset) + self.current_mode = guildchannels.get( + self.current_channel.id, ChannelType.unset + ) self.update_state() def regenerate_matches( self, parent:ConfessionsSetup, guild:discord.Guild - ) -> tuple[discord.TextChannel, ChannelType]: + ) -> list[tuple[discord.TextChannel, ChannelType]]: """ Create a list of all channels on the server sorted by categories and position """ if len(guild.channels) == 0: return [] From 5dfda1344b799039dfa1d7aac1624bcab9168a08 Mon Sep 17 00:00:00 2001 From: Yiays Date: Thu, 24 Jul 2025 22:50:28 +1200 Subject: [PATCH 4/7] Beta launch v2.8.0 --- config/config.factory.ini | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/config/config.factory.ini b/config/config.factory.ini index a280f3f..deaa1b1 100755 --- a/config/config.factory.ini +++ b/config/config.factory.ini @@ -5,7 +5,7 @@ themecolor = 0x000000 voteurl = tos_url = beta = False -ver = 2.7.1 +ver = 2.8.0 creator = [intents] @@ -190,6 +190,10 @@ changelog = > 1.0.0 - Encryption for sensitive user data has been improved > 2.7.1 - Added support for mentions in confession branding while in compact mode + > 2.8.0 + - Active threads can now be confessed to, alongside the set channels that contain them. + - Translators can now rename commands and translate their descriptions. + - Flags are now shown in `/language` commands. [premium] icon = From 89aa0e4d6b3423ca80e8ac0d04011c5bfb5ba7ef Mon Sep 17 00:00:00 2001 From: Yiays Date: Sat, 26 Jul 2025 20:13:24 +1200 Subject: [PATCH 5/7] Update to discord.py 2.5.2 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d7c5aa9..306a525 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ -discord.py==2.5.0 +discord.py==2.5.2 pycryptodome \ No newline at end of file From 24bfcdefea6fdedf4ee4979f104b71de8b856036 Mon Sep 17 00:00:00 2001 From: Yiays Date: Sat, 26 Jul 2025 22:40:36 +1200 Subject: [PATCH 6/7] /confess can now be renamed on a per-server basis Creates another command with the same functionality as /confess, but with a different name on each server --- babel/confessionbot_en.ini | 5 ++- config/config.factory.ini | 1 + extensions/confessions.py | 60 ++++++++++++++++++++++++++++++++- extensions/confessions_setup.py | 3 +- 4 files changed, 66 insertions(+), 3 deletions(-) diff --git a/babel/confessionbot_en.ini b/babel/confessionbot_en.ini index 4dd1919..8702583 100755 --- a/babel/confessionbot_en.ini +++ b/babel/confessionbot_en.ini @@ -28,9 +28,11 @@ about_field5_value = **Support development and get some nice aesthetic perks for [premium] feature_1 = Compact mode -feature_1_desc = **Enjoy confessions in a new compact style!** - When compact confessions is enabled, every member on your server gets an Anon-ID user and profile picture so messages don't need as much space. *Enable this in {p:controlpanel}*. +feature_1_desc = **Enjoy confessions in a new compact style!** - When compact confessions are enabled, every member on your server gets an Anon-ID user and profile picture so messages don't need as much space. *Enable this in {p:controlpanel}*. feature_2 = Make {c:main/botname} your server's feature_2_desc = **Add a branding message above every confession** - You could mention a role, or name your server. *Enable this in {p:controlpanel}*. + + **Rename /confess** - Change the name of the {p:confess} command to tightly integrate {c:main/botname} into your server. *Enable this in {p:controlpanel}*. feature_custom_desc = **DM Confessions and custom features available** - Get in touch with {c:main/creator} in the (support server)[{c:help/serverinv}] about your custom requirements. *This requires a more expensive tier of support*. [confessions] @@ -95,6 +97,7 @@ guild_banlist = Banned Anon-IDs image_support = Image support enable_webhooks = Compact confessions confession_preface = Confession branding +confess_custom_name = Custom /confess command ; errors inaccessible = There's no anonymous channels you can access. *An admin needs to {p:setup} a channel to start.* diff --git a/config/config.factory.ini b/config/config.factory.ini index deaa1b1..b089287 100755 --- a/config/config.factory.ini +++ b/config/config.factory.ini @@ -194,6 +194,7 @@ changelog = > 1.0.0 - Active threads can now be confessed to, alongside the set channels that contain them. - Translators can now rename commands and translate their descriptions. - Flags are now shown in `/language` commands. + - Premium users can now set a custom name for the `/confess` command. [premium] icon = diff --git a/extensions/confessions.py b/extensions/confessions.py index 87d51eb..d8c1dd5 100755 --- a/extensions/confessions.py +++ b/extensions/confessions.py @@ -13,7 +13,7 @@ from typing import Optional, Union, TYPE_CHECKING import discord from discord import app_commands -from discord.ext import commands +from discord.ext import commands, tasks if TYPE_CHECKING: from main import MerelyBot @@ -29,6 +29,7 @@ class Confessions(commands.Cog): """ Facilitates anonymous messaging with moderation on your server """ SCOPE = 'confessions' + customcommands: dict[int, str] = {} @property def config(self) -> SectionProxy: @@ -78,9 +79,44 @@ def __init__(self, bot:MerelyBot): callback=self.confess_reply_callback ) bot.tree.add_command(self.confess_reply) + self.bind_custom_commands.start() async def cog_unload(self): + self.bind_custom_commands.stop() self.bot.tree.remove_command(self.confess_reply.qualified_name, type=self.confess_reply.type) + for guild_id, cmdname in self.customcommands.items(): + self.bot.tree.remove_command(cmdname, guild=discord.Object(guild_id)) + + @tasks.loop(seconds=10) + async def bind_custom_commands(self): + """ If any users have requested a custom name for /confess, bind it to the tree """ + for guild in self.bot.guilds: + customname = self.config.get(f'{guild.id}_confessname') + if customname: + if guild.id in self.customcommands: + # Check if custom command already exists + if self.customcommands[guild.id] == customname: + # No need to rebind unless the name changes + continue + self.bot.tree.remove_command(self.customcommands[guild.id], guild=guild) + self.customcommands[guild.id] = customname + self.bot.tree.add_command( + app_commands.Command( + name=customname, + description=app_commands.locale_str('confess_desc', scope=self.SCOPE), + callback=self.renamed_confess_callback, + guild_ids=[guild.id], + allowed_contexts=app_commands.AppCommandContext(guild=True) + ) + ) + await self.bot.tree.sync(guild=guild) + #if self.bot.verbose: + print(f"Bound custom command /{customname} to guild {guild.name}") + else: + # Remove custom command if it exists + if guild.id in self.customcommands: + self.bot.tree.remove_command(self.customcommands[guild.id], guild=guild) + await self.bot.tree.sync(guild=guild) # Context menu commands @@ -94,6 +130,28 @@ async def confess_reply_callback(self, inter:discord.Interaction, message:discor data.create(author=inter.user, target=inter.channel, reference=message) await self.verify_and_send(inter, data) + @app_commands.describe( + content=app_commands.locale_str('confess_content_desc', scope=SCOPE), + image=app_commands.locale_str('confess_image_desc', scope=SCOPE) + ) + @commands.cooldown(1, 1, type=commands.BucketType.user) + async def renamed_confess_callback( + self, + inter:discord.Interaction, + content:Optional[app_commands.Range[str, 0, 3900]] = None, + image:Optional[discord.Attachment] = None + ): + """ + Send an anonymous message to this channel + """ + pendingconfession = ConfessionData(self) + pendingconfession.create(author=inter.user, target=inter.channel) + pendingconfession.set_content(content) + if image: + await inter.response.defer(ephemeral=True) + await pendingconfession.add_image(attachment=image) + await self.verify_and_send(inter, pendingconfession) + # Utility functions def generate_list( diff --git a/extensions/confessions_setup.py b/extensions/confessions_setup.py index 8641880..ecf076c 100644 --- a/extensions/confessions_setup.py +++ b/extensions/confessions_setup.py @@ -62,7 +62,8 @@ def controlpanel_settings(self, inter:discord.Interaction): out += [ Toggleable(self.SCOPE, f'{inter.guild_id}_imagesupport', 'image_support', default=True), Toggleable(self.SCOPE, f'{inter.guild_id}_webhook', 'enable_webhooks', default=False), - Stringable(self.SCOPE, f'{inter.guild_id}_preface', 'confession_preface') + Stringable(self.SCOPE, f'{inter.guild_id}_preface', 'confession_preface'), + Stringable(self.SCOPE, f'{inter.guild_id}_confessname', 'confess_custom_name', r'\p{L}{1,32}') #TODO: Add custom pfp stringable, Anon-ID usernames, Anon-Colour pfps ] return out From 2fb6083c3bcd3625f77a7633ba8de3149268d948 Mon Sep 17 00:00:00 2001 From: Yiays Date: Sat, 26 Jul 2025 22:40:54 +1200 Subject: [PATCH 7/7] Fix issues related to translatable command names --- extensions/confessions.py | 25 ++++++++++++++----------- extensions/confessions_marketplace.py | 14 +++++++------- extensions/confessions_moderation.py | 10 +++++----- extensions/confessions_setup.py | 8 ++++---- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/extensions/confessions.py b/extensions/confessions.py index d8c1dd5..88a3a95 100755 --- a/extensions/confessions.py +++ b/extensions/confessions.py @@ -73,7 +73,7 @@ def __init__(self, bot:MerelyBot): self.confession_cooldown = dict() self.confess_reply = app_commands.ContextMenu( - name=app_commands.locale_str('command_Confession_Reply', scope=self.SCOPE), + name=app_commands.locale_str('Confession_Reply', scope=self.SCOPE), allowed_contexts=app_commands.AppCommandContext(guild=True, private_channel=False), allowed_installs=app_commands.AppInstallationType(guild=True, user=False), callback=self.confess_reply_callback @@ -359,13 +359,13 @@ async def confession_request(self, msg:discord.Message): # Slash commands @app_commands.command( - name=app_commands.locale_str('command_confess', scope=SCOPE), - description=app_commands.locale_str('command_confess_desc', scope=SCOPE) + name=app_commands.locale_str('confess', scope=SCOPE), + description=app_commands.locale_str('confess_desc', scope=SCOPE) ) @app_commands.allowed_contexts(guilds=True) @app_commands.describe( - content=app_commands.locale_str('command_confess_content_desc', scope=SCOPE), - image=app_commands.locale_str('command_confess_image_desc', scope=SCOPE) + content=app_commands.locale_str('confess_content_desc', scope=SCOPE), + image=app_commands.locale_str('confess_image_desc', scope=SCOPE) ) @commands.cooldown(1, 1, type=commands.BucketType.user) async def confess( @@ -385,12 +385,15 @@ async def confess( await pendingconfession.add_image(attachment=image) await self.verify_and_send(inter, pendingconfession) - @app_commands.command(name='confess-to') + @app_commands.command( + name=app_commands.locale_str('confess-to', scope=SCOPE), + description=app_commands.locale_str('confess-to_desc', scope=SCOPE) + ) @app_commands.allowed_contexts(guilds=True) @app_commands.describe( - channel=app_commands.locale_str('command_confess-to_channel_desc', scope=SCOPE), - content=app_commands.locale_str('command_confess_content_desc', scope=SCOPE), - image=app_commands.locale_str('command_confess_image_desc', scope=SCOPE) + channel=app_commands.locale_str('confess-to_channel_desc', scope=SCOPE), + content=app_commands.locale_str('confess_content_desc', scope=SCOPE), + image=app_commands.locale_str('confess_image_desc', scope=SCOPE) ) @commands.cooldown(1, 1, type=commands.BucketType.user) async def confess_to( @@ -450,8 +453,8 @@ async def channel_ac(self, inter:discord.Interaction, search:str): ) @app_commands.command( - name=app_commands.locale_str('command_list', scope=SCOPE), - description=app_commands.locale_str('command_list_desc', scope=SCOPE) + name=app_commands.locale_str('list', scope=SCOPE), + description=app_commands.locale_str('list_desc', scope=SCOPE) ) async def list(self, inter:discord.Interaction): """ diff --git a/extensions/confessions_marketplace.py b/extensions/confessions_marketplace.py index f19fb4b..6fc3945 100644 --- a/extensions/confessions_marketplace.py +++ b/extensions/confessions_marketplace.py @@ -232,16 +232,16 @@ async def on_withdraw(self, inter:discord.Interaction): # Slash commands @app_commands.command( - name=app_commands.locale_str('command_sell', scope=SCOPE), - description=app_commands.locale_str('command_sell_desc', scope=SCOPE) + name=app_commands.locale_str('sell', scope=SCOPE), + description=app_commands.locale_str('sell_desc', scope=SCOPE) ) @app_commands.allowed_contexts(guilds=True) @app_commands.describe( - title=app_commands.locale_str('command_sell_title_desc', scope=SCOPE), - starting_price=app_commands.locale_str('command_sell_starting_price_desc', scope=SCOPE), - payment_methods=app_commands.locale_str('command_sell_payment_methods_desc', scope=SCOPE), - description=app_commands.locale_str('command_sell_description_desc', scope=SCOPE), - image=app_commands.locale_str('command_sell_image_desc', scope=SCOPE) + title=app_commands.locale_str('sell_title_desc', scope=SCOPE), + starting_price=app_commands.locale_str('sell_starting_price_desc', scope=SCOPE), + payment_methods=app_commands.locale_str('sell_payment_methods_desc', scope=SCOPE), + description=app_commands.locale_str('sell_description_desc', scope=SCOPE), + image=app_commands.locale_str('sell_image_desc', scope=SCOPE) ) @commands.cooldown(1, 1, type=commands.BucketType.user) async def sell( diff --git a/extensions/confessions_moderation.py b/extensions/confessions_moderation.py index 24971ec..493e626 100644 --- a/extensions/confessions_moderation.py +++ b/extensions/confessions_moderation.py @@ -53,7 +53,7 @@ def __init__(self, bot:MerelyBot): raise Exception("Module `confessions` must be enabled!") self.report = app_commands.ContextMenu( - name=app_commands.locale_str('command_Confession_Report', scope=self.SCOPE), + name=app_commands.locale_str('Confession_Report', scope=self.SCOPE), allowed_contexts=app_commands.AppCommandContext(guild=True, private_channel=False), allowed_installs=app_commands.AppInstallationType(guild=True, user=False), callback=self.report_callback @@ -335,12 +335,12 @@ async def on_confession_review(self, inter:discord.Interaction): # Commands @app_commands.command( - name=app_commands.locale_str('command_block', scope=SCOPE), - description=app_commands.locale_str('command_block_desc', scope=SCOPE) + name=app_commands.locale_str('block', scope=SCOPE), + description=app_commands.locale_str('block_desc', scope=SCOPE) ) @app_commands.describe( - anonid=app_commands.locale_str('command_block_anonid_desc', scope=SCOPE), - unblock=app_commands.locale_str('command_block_unblock_desc', scope=SCOPE) + anonid=app_commands.locale_str('block_anonid_desc', scope=SCOPE), + unblock=app_commands.locale_str('block_unblock_desc', scope=SCOPE) ) @app_commands.allowed_contexts(guilds=True, private_channels=False) @app_commands.default_permissions(moderate_members=True) diff --git a/extensions/confessions_setup.py b/extensions/confessions_setup.py index ecf076c..0b75ccb 100644 --- a/extensions/confessions_setup.py +++ b/extensions/confessions_setup.py @@ -370,8 +370,8 @@ async def channel_cleanup(self, channel:discord.TextChannel): # Commands @app_commands.command( - name=app_commands.locale_str('command_setup', scope=SCOPE), - description=app_commands.locale_str('command_setup_desc', scope=SCOPE) + name=app_commands.locale_str('setup', scope=SCOPE), + description=app_commands.locale_str('setup_desc', scope=SCOPE) ) @app_commands.allowed_contexts(guilds=True) @app_commands.default_permissions(manage_channels=True) @@ -386,8 +386,8 @@ async def setup(self, inter:discord.Interaction): ) @app_commands.command( - name=app_commands.locale_str('command_shuffle', scope=SCOPE), - description=app_commands.locale_str('command_shuffle_desc', scope=SCOPE) + name=app_commands.locale_str('shuffle', scope=SCOPE), + description=app_commands.locale_str('shuffle_desc', scope=SCOPE) ) @app_commands.allowed_contexts(guilds=True) @app_commands.default_permissions(moderate_members=True)