Skip to content

Commit 457ad9e

Browse files
authored
Merge pull request #4 from martinbndr/recipient_thread_close_button
recipient_thread_close via Buttons
2 parents e798fb5 + e3af5fa commit 457ad9e

File tree

5 files changed

+106
-29
lines changed

5 files changed

+106
-29
lines changed

bot.py

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,15 @@
4848
)
4949
from core.thread import ThreadManager
5050
from core.time import human_timedelta
51-
from core.utils import extract_block_timestamp, normalize_alias, parse_alias, truncate, tryint, human_join
51+
from core.utils import (
52+
extract_block_timestamp,
53+
normalize_alias,
54+
parse_alias,
55+
truncate,
56+
tryint,
57+
human_join,
58+
ThreadSelfCloseView,
59+
)
5260

5361
logger = getLogger(__name__)
5462

@@ -617,6 +625,7 @@ async def on_ready(self):
617625
self.post_metadata.start()
618626
self.autoupdate.start()
619627
self.log_expiry.start()
628+
self.add_view(ThreadSelfCloseView(self))
620629
self._started = True
621630

622631
async def convert_emoji(self, name: str) -> str:
@@ -1275,19 +1284,7 @@ async def handle_reaction_events(self, payload):
12751284
return
12761285

12771286
reaction = payload.emoji
1278-
close_emoji = await self.convert_emoji(self.config["close_emoji"])
12791287
if from_dm:
1280-
if (
1281-
payload.event_type == "REACTION_ADD"
1282-
and message.embeds
1283-
and str(reaction) == str(close_emoji)
1284-
and self.config.get("recipient_thread_close")
1285-
):
1286-
ts = message.embeds[0].timestamp
1287-
if ts == thread.channel.created_at:
1288-
# the reacted message is the corresponding thread creation embed
1289-
# closing thread
1290-
return await thread.close(closer=user)
12911288
if (
12921289
message.author == self.user
12931290
and message.embeds

core/config.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,14 @@ class ConfigManager:
4949
# threads
5050
"sent_emoji": "\N{WHITE HEAVY CHECK MARK}",
5151
"blocked_emoji": "\N{NO ENTRY SIGN}",
52-
"close_emoji": "\N{LOCK}",
52+
"close_emoji": None,
5353
"use_user_id_channel_name": False,
5454
"use_timestamp_channel_name": False,
5555
"use_nickname_channel_name": False,
5656
"use_random_channel_name": False,
5757
"recipient_thread_close": False,
58+
"recipient_thread_close_button_label": None,
59+
"recipient_thread_close_button_style": "red",
5860
"thread_show_roles": True,
5961
"thread_show_account_age": True,
6062
"thread_show_join_age": True,
@@ -65,7 +67,7 @@ class ConfigManager:
6567
"thread_creation_response": "The staff team will get back to you as soon as possible.",
6668
"thread_creation_footer": "Your message has been sent",
6769
"thread_contact_silently": False,
68-
"thread_self_closable_creation_footer": "Click the lock to close the thread",
70+
"thread_self_closable_creation_footer": "Click the button to close the thread",
6971
"thread_creation_contact_title": "New Thread",
7072
"thread_creation_self_contact_response": "You have opened a Modmail thread.",
7173
"thread_creation_contact_response": "{creator.name} has opened a Modmail thread.",
@@ -230,11 +232,7 @@ class ConfigManager:
230232
"registry_plugins_only",
231233
}
232234

233-
enums = {
234-
"dm_disabled": DMDisabled,
235-
"status": discord.Status,
236-
"activity_type": discord.ActivityType,
237-
}
235+
enums = {"dm_disabled": DMDisabled, "status": discord.Status, "activity_type": discord.ActivityType}
238236

239237
force_str = {"command_permissions", "level_permissions"}
240238

core/config_help.json

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,8 @@
285285
]
286286
},
287287
"close_emoji": {
288-
"default": "🔒",
289-
"description": "This is the emoji the recipient can click to close a thread themselves. The emoji is automatically added to the `thread_creation_response` embed.",
288+
"default": "None",
289+
"description": "This is the emoji for the close button the recipient can click to close a thread themselves. The emoji (attached to the button) is automatically added to the `thread_creation_response` embed.",
290290
"examples": [
291291
"`{prefix}config set close_emoji 👍‍`"
292292
],
@@ -297,14 +297,37 @@
297297
},
298298
"recipient_thread_close": {
299299
"default": "Disabled",
300-
"description": "Setting this configuration will allow recipients to use the `close_emoji` to close the thread themselves.",
300+
"description": "Setting this configuration will allow recipients to close threads by themselves via a button.",
301301
"examples": [
302302
"`{prefix}config set recipient_thread_close yes`",
303303
"`{prefix}config set recipient_thread_close no`"
304304
],
305305
"notes": [
306-
"The close emoji is dictated by the configuration `close_emoji`.",
307-
"See also: `close_emoji`."
306+
"The button attached to the `thread_creation_response` can have set a custom label, emoji or even both.",
307+
"See also: `close_emoji`, `recipient_thread_close_button_label`, `recipient_thread_close_button_style`."
308+
]
309+
},
310+
"recipient_thread_close_button_label": {
311+
"default": "None",
312+
"description": "This configuration changes the label of the button for the `recipient_thread_close` feature.",
313+
"examples": [
314+
"`{prefix}config set recipient_thread_close_button_label Your label`"
315+
],
316+
"notes": [
317+
"The label cannot exceed 80 characters.",
318+
"See also: `recipient_thread_close`, `close_emoji`, `recipient_thread_close_button_style`."
319+
]
320+
},
321+
"recipient_thread_close_button_style": {
322+
"default": "red",
323+
"description": "This configuration changes the style of the button for the `recipient_thread_close` feature.",
324+
"examples": [
325+
"`{prefix}config set recipient_thread_close_button_style green`",
326+
"`{prefix}config set recipient_thread_close_button_style blurple`"
327+
],
328+
"notes": [
329+
"The style is limited by discord to the following colors: blurple, green, red, gray.",
330+
"See also: `recipient_thread_close`, `close_emoji`, `recipient_thread_close_button_label`."
308331
]
309332
},
310333
"thread_show_roles": {

core/thread.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
AcceptButton,
3333
DenyButton,
3434
ConfirmThreadCreationView,
35+
ThreadSelfCloseView,
3536
DummyParam,
3637
)
3738

@@ -239,11 +240,33 @@ async def send_recipient_genesis_message():
239240

240241
if creator is None or creator == recipient:
241242
msg = await recipient.send(embed=embed)
242-
243-
if recipient_thread_close:
243+
close_emoji = self.bot.config["close_emoji"]
244+
close_label = self.bot.config["recipient_thread_close_button_label"]
245+
if (
246+
recipient_thread_close
247+
and self.bot.config["recipient_thread_close_button_style"].lower()
248+
in ["red", "green", "blurple", "gray"]
249+
and (close_emoji is not None and close_label is not None)
250+
):
244251
close_emoji = self.bot.config["close_emoji"]
245-
close_emoji = await self.bot.convert_emoji(close_emoji)
246-
await self.bot.add_reaction(msg, close_emoji)
252+
if close_emoji:
253+
close_emoji = await self.bot.convert_emoji(close_emoji)
254+
255+
button_style = discord.ButtonStyle(
256+
int(
257+
discord.ButtonStyle[
258+
self.bot.config["recipient_thread_close_button_style"].lower()
259+
]
260+
)
261+
)
262+
view = ThreadSelfCloseView(
263+
button_style,
264+
close_label,
265+
close_emoji,
266+
self.bot,
267+
)
268+
await msg.edit(view=view)
269+
# await self.bot.add_reaction(msg, close_emoji)
247270

248271
async def send_persistent_notes():
249272
notes = await self.bot.api.find_notes(self.recipient)

core/utils.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"AcceptButton",
4343
"DenyButton",
4444
"ConfirmThreadCreationView",
45+
"ThreadSelfCloseView",
4546
"DummyParam",
4647
]
4748

@@ -599,6 +600,41 @@ def __init__(self):
599600
self.value = None
600601

601602

603+
class ThreadSelfCloseView(discord.ui.View):
604+
def __init__(
605+
self,
606+
style: typing.Optional[discord.ButtonStyle] = None,
607+
label: typing.Optional[str] = None,
608+
emoji: typing.Optional[str] = None,
609+
bot: typing.Any = None,
610+
):
611+
super().__init__(timeout=None)
612+
self.bot = bot
613+
614+
self.self_close_button.label = label
615+
self.self_close_button.style = style
616+
self.self_close_button.emoji = emoji
617+
618+
@discord.ui.button(label="default", style=discord.ButtonStyle.secondary, custom_id="SelfCloseView")
619+
async def self_close_button(self, interaction: discord.Interaction, button: discord.ui.Button):
620+
await interaction.response.defer(ephemeral=False, thinking=True)
621+
thread = await self.bot.threads.find(recipient=interaction.user)
622+
if not thread:
623+
error_embed = discord.Embed(
624+
description="A thread could not be found.", color=self.bot.config["error_color"]
625+
)
626+
return await interaction.followup.send(embed=error_embed)
627+
628+
message = self.bot.config["thread_self_close_response"]
629+
embed = discord.Embed(
630+
title="Thread closed", description=message, color=self.bot.config["error_color"]
631+
)
632+
await thread.close(closer=interaction.user, silent=True)
633+
self.self_close_button.disabled = True
634+
await interaction.message.edit(view=self)
635+
await interaction.followup.send(embed=embed)
636+
637+
602638
class DummyParam:
603639
"""
604640
A dummy parameter that can be used for MissingRequiredArgument.

0 commit comments

Comments
 (0)