1
1
import typing
2
- import aiohttp
3
- from ext .consts import MODMAIL_CHANNEL_ID , MODMAIL_WEBHOOK_URL
2
+ from ext .consts import MODMAIL_CHANNEL_ID , MODMAIL_ROLE_ID , MODMAIL_CLOSED , MODMAIL_OPEN
4
3
from discord .ext import commands
5
4
import discord
6
5
from ext .ui .view import YesNoView
7
- import os
8
6
7
+ def none_if_error (func ):
8
+ def wrapper (* args , ** kwargs ):
9
+ try :
10
+ return func (* args , ** kwargs )
11
+ except Exception :
12
+ return None
13
+
14
+ return wrapper
9
15
10
16
class ModMail (commands .Cog ):
11
17
def __init__ (self , bot : commands .Bot ):
12
18
self .bot = bot
13
- self .current_modmail = {}
14
- self .opposite_current_modmail = {}
15
- self .channel : typing .Optional [discord .TextChannel ] = None
19
+ self .sessions = [] # [{user: discord.Member, thread: discord.Thread}]
20
+ self .channel : typing .Optional [discord .ForumChannel ] = None
21
+
22
+ @none_if_error
23
+ def get_thread (self , user ) -> discord .Thread | None :
24
+ return [i ['thread' ] for i in self .sessions if i ['user' ] == user ][0 ]
25
+
26
+ @none_if_error
27
+ def get_user (self , thread ) -> discord .Member | discord .User | None :
28
+ return [i ['user' ] for i in self .sessions if i ['thread' ] == thread ][0 ]
29
+
30
+ async def send_webhook_message (
31
+ self ,
32
+ message : discord .Message ,
33
+ thread : discord .Thread
34
+ ):
35
+ webhook = thread .parent .webhooks ()[0 ]
36
+ await webhook .send (
37
+ username = message .author .name ,
38
+ content = message .content ,
39
+ avatar_url = message .author .display_avatar .url ,
40
+ files = message .attachments ,
41
+ allowed_mentions = discord .AllowedMentions (
42
+ users = False , everyone = False , roles = False
43
+ ),
44
+ thread = thread ,
45
+ )
46
+ await message .add_reaction ("✅" )
47
+
48
+ async def close_thread (self , thread : discord .Thread ):
49
+ await thread .add_tags (thread .parent .get_tag (MODMAIL_CLOSED ))
50
+ await thread .remove_tags (thread .parent .get_tag (MODMAIL_OPEN ))
51
+ await thread .edit (locked = True , archived = True )
52
+ self .sessions .remove ({'user' : self .get_user (thread ), 'thread' : thread })
16
53
17
54
@commands .hybrid_command ()
18
- async def close (self , ctx ):
19
- if not ctx .guild :
20
- if ctx .author in self .current_modmail :
21
- thread = self .current_modmail [ctx .author ]
22
- await thread .edit (locked = True )
23
- self .current_modmail .pop (ctx .author )
24
- self .opposite_current_modmail .pop (thread )
25
- await ctx .send ("Your modmail ticket has successfully closed!" )
26
- elif ctx .channel in self .opposite_current_modmail :
27
- member = self .opposite_current_modmail [ctx .channel ]
55
+ async def close (self , ctx : commands .Context ):
56
+ if not ctx .guild and (thread := self .get_thread (ctx .author )):
57
+ await thread .send ("This ticket has been closed by the user." )
58
+ await self .close_thread (thread )
59
+ await ctx .send ("Your modmail ticket has successfully closed!" )
60
+
61
+ elif member := self .get_user (ctx .channel ):
28
62
view = YesNoView (
29
63
yes_message = "Your modmail ticket has successfully closed!" ,
30
64
no_message = "Aborted." ,
31
65
)
32
66
await member .send (content = "Do you want to close the ticket?" , view = view )
33
67
await view .wait ()
34
68
if view .yes :
35
- await ctx .channel .edit (locked = True )
36
- self .current_modmail .pop (member )
37
- self .opposite_current_modmail .pop (ctx .channel )
69
+ await self .close_thread (ctx .channel )
38
70
else :
39
71
await ctx .channel .send ("Member refused to close the ticket." )
40
72
41
73
@commands .Cog .listener ()
42
74
async def on_message (self , message : discord .Message ):
43
- if (
44
- not self .channel
45
- ): # I was unsure if getting the channel in the __init__ is wise
46
- self .channel = self .bot .get_channel (MODMAIL_CHANNEL_ID )
75
+ if not self .channel :
76
+ self .channel : discord .ForumChannel = self .bot .get_channel (MODMAIL_CHANNEL_ID )
47
77
48
- if message .author .bot or message .content .startswith (self .bot .command_prefix ):
78
+ if message .author .bot or message .content .startswith (self .bot .command_prefix [ 0 ] ):
49
79
return
50
80
51
81
if not message .guild :
52
- if message . author not in self .current_modmail :
82
+ if not ( thread := self .get_thread ( message . author )) :
53
83
view = YesNoView (
54
84
yes_message = "Your modmail ticket has been successfully created!" ,
55
85
no_message = "Aborted." ,
@@ -59,37 +89,24 @@ async def on_message(self, message: discord.Message):
59
89
)
60
90
await view .wait ()
61
91
if view .yes :
62
- msg_sent = await self .channel .send (
63
- message .content ,
92
+ thread , _ = await self .channel .create_thread (
93
+ name = f"Modmail @{ message .author .name } " ,
94
+ content = "New ModMail ticket created by " \
95
+ f"{ message .author .mention } , <@&{ MODMAIL_ROLE_ID } >" ,
64
96
files = message .attachments ,
65
- allowed_mentions = discord .AllowedMentions (
66
- users = False , everyone = False , roles = False
67
- ),
68
- )
69
- thread = await self .channel .create_thread (
70
- name = f"{ message .author .name } vs mods" , message = msg_sent
97
+ applied_tags = [self .channel .get_tag (MODMAIL_OPEN )],
71
98
)
72
- self .current_modmail [message .author ] = thread
73
- self .opposite_current_modmail [thread ] = message .author
99
+ await self .send_webhook_message (message , thread )
100
+
101
+ self .sessions .append ({'user' : message .author , 'thread' : thread })
74
102
else :
75
- thread = self .current_modmail [message .author ]
76
- async with aiohttp .ClientSession () as session :
77
- webhook = discord .Webhook .from_url (
78
- MODMAIL_WEBHOOK_URL , session = session
79
- )
80
- await webhook .send (
81
- content = message .content ,
82
- avatar_url = message .author .display_avatar .url ,
83
- files = message .attachments ,
84
- allowed_mentions = discord .AllowedMentions (
85
- users = False , everyone = False , roles = False
86
- ),
87
- thread = thread ,
88
- )
89
- await message .add_reaction ("✅" )
90
- elif message .channel in self .opposite_current_modmail :
91
- member = self .opposite_current_modmail [message .channel ]
92
- await member .send ("⚒️ staff: " + message .content , files = message .attachments )
103
+ await self .send_webhook_message (message , thread )
104
+
105
+ elif member := self .get_user (message .channel ):
106
+ await member .send (
107
+ f"⚒️ @{ message .author .name } : " + message .content ,
108
+ files = message .attachments
109
+ )
93
110
94
111
95
112
async def setup (bot ):
0 commit comments