2121 match_user_id ,
2222 match_other_recipients ,
2323 truncate ,
24- format_channel_name ,
2524 get_top_hoisted_role ,
25+ create_thread_channel ,
26+ get_joint_id ,
2627)
2728
2829logger = getLogger (__name__ )
@@ -36,7 +37,7 @@ def __init__(
3637 manager : "ThreadManager" ,
3738 recipient : typing .Union [discord .Member , discord .User , int ],
3839 channel : typing .Union [discord .DMChannel , discord .TextChannel ] = None ,
39- other_recipients : typing .List [typing .Union [discord .Member , discord .User ]] = [] ,
40+ other_recipients : typing .List [typing .Union [discord .Member , discord .User ]] = None ,
4041 ):
4142 self .manager = manager
4243 self .bot = manager .bot
@@ -48,7 +49,7 @@ def __init__(
4849 raise CommandError ("Recipient cannot be a bot." )
4950 self ._id = recipient .id
5051 self ._recipient = recipient
51- self ._other_recipients = other_recipients
52+ self ._other_recipients = other_recipients or []
5253 self ._channel = channel
5354 self .genesis_message = None
5455 self ._ready_event = asyncio .Event ()
@@ -127,9 +128,13 @@ async def from_channel(cls, manager: "ThreadManager", channel: discord.TextChann
127128 else :
128129 recipient = manager .bot .get_user (recipient_id ) or await manager .bot .fetch_user (recipient_id )
129130
130- other_recipients = match_other_recipients (channel .topic )
131- for n , uid in enumerate (other_recipients ):
132- other_recipients [n ] = manager .bot .get_user (uid ) or await manager .bot .fetch_user (uid )
131+ other_recipients = []
132+ for uid in match_other_recipients (channel .topic ):
133+ try :
134+ other_recipient = manager .bot .get_user (uid ) or await manager .bot .fetch_user (uid )
135+ except discord .NotFound :
136+ continue
137+ other_recipients .append (other_recipient )
133138
134139 thread = cls (manager , recipient or recipient_id , channel , other_recipients )
135140
@@ -149,33 +154,19 @@ async def setup(self, *, creator=None, category=None, initial_message=None):
149154 overwrites = None
150155
151156 try :
152- channel = await self .bot .modmail_guild .create_text_channel (
153- name = format_channel_name (self .bot , recipient ),
154- category = category ,
155- overwrites = overwrites ,
156- reason = "Creating a thread channel." ,
157- )
158- except discord .HTTPException as e :
159- # try again but null-discrim (name could be banned)
160- try :
161- channel = await self .bot .modmail_guild .create_text_channel (
162- name = format_channel_name (self .bot , recipient , force_null = True ),
163- category = category ,
164- overwrites = overwrites ,
165- reason = "Creating a thread channel." ,
166- )
167- except discord .HTTPException as e : # Failed to create due to missing perms.
168- logger .critical ("An error occurred while creating a thread." , exc_info = True )
169- self .manager .cache .pop (self .id )
157+ channel = await create_thread_channel (self .bot , recipient , category , overwrites )
158+ except discord .HTTPException as e : # Failed to create due to missing perms.
159+ logger .critical ("An error occurred while creating a thread." , exc_info = True )
160+ self .manager .cache .pop (self .id )
170161
171- embed = discord .Embed (color = self .bot .error_color )
172- embed .title = "Error while trying to create a thread."
173- embed .description = str (e )
174- embed .add_field (name = "Recipient" , value = recipient .mention )
162+ embed = discord .Embed (color = self .bot .error_color )
163+ embed .title = "Error while trying to create a thread."
164+ embed .description = str (e )
165+ embed .add_field (name = "Recipient" , value = recipient .mention )
175166
176- if self .bot .log_channel is not None :
177- await self .bot .log_channel .send (embed = embed )
178- return
167+ if self .bot .log_channel is not None :
168+ await self .bot .log_channel .send (embed = embed )
169+ return
179170
180171 self ._channel = channel
181172
@@ -209,7 +200,7 @@ async def send_genesis_message():
209200 logger .error ("Failed unexpectedly:" , exc_info = True )
210201
211202 async def send_recipient_genesis_message ():
212- # Once thread is ready, tell the recipient.
203+ # Once thread is ready, tell the recipient (don't send if using contact on others)
213204 thread_creation_response = self .bot .config ["thread_creation_response" ]
214205
215206 embed = discord .Embed (
@@ -585,7 +576,7 @@ async def find_linked_messages(
585576 either_direction : bool = False ,
586577 message1 : discord .Message = None ,
587578 note : bool = True ,
588- ) -> typing .Tuple [discord .Message , typing .Optional [discord .Message ]]:
579+ ) -> typing .Tuple [discord .Message , typing .List [ typing . Optional [discord .Message ] ]]:
589580 if message1 is not None :
590581 if not message1 .embeds or not message1 .embeds [0 ].author .url or message1 .author != self .bot .user :
591582 raise ValueError ("Malformed thread message." )
@@ -698,49 +689,84 @@ async def delete_message(
698689 if tasks :
699690 await asyncio .gather (* tasks )
700691
701- async def find_linked_message_from_dm (self , message , either_direction = False ):
702- if either_direction and message .embeds and message .embeds [0 ].author .url :
703- compare_url = message .embeds [0 ].author .url
704- compare_id = compare_url .split ("#" )[- 1 ]
705- else :
706- compare_url = None
707- compare_id = None
692+ async def find_linked_message_from_dm (
693+ self , message , either_direction = False
694+ ) -> typing .List [discord .Message ]:
695+
696+ joint_id = None
697+ if either_direction :
698+ joint_id = get_joint_id (message )
699+ # could be None too, if that's the case we'll reassign this variable from
700+ # thread message we fetch in the next step
708701
702+ linked_messages = []
709703 if self .channel is not None :
710- async for linked_message in self .channel .history ():
711- if not linked_message .embeds :
704+ async for msg in self .channel .history ():
705+ if not msg .embeds :
712706 continue
713- url = linked_message .embeds [0 ].author .url
714- if not url :
715- continue
716- if url == compare_url :
717- return linked_message
718707
719- msg_id = url . split ( "#" )[ - 1 ]
720- if not msg_id . isdigit () :
708+ msg_joint_id = get_joint_id ( msg )
709+ if msg_joint_id is None :
721710 continue
722- msg_id = int (msg_id )
723- if int (msg_id ) == message .id :
724- return linked_message
725711
726- if compare_id is not None and compare_id . isdigit () :
727- if int ( msg_id ) == int ( compare_id ):
728- return linked_message
712+ if msg_joint_id == message . id :
713+ linked_messages . append ( msg )
714+ break
729715
716+ if joint_id is not None and msg_joint_id == joint_id :
717+ linked_messages .append (msg )
718+ break
719+ else :
720+ raise ValueError ("Thread channel message not found." )
721+ else :
730722 raise ValueError ("Thread channel message not found." )
731723
724+ if joint_id is None :
725+ joint_id = get_joint_id (linked_messages [0 ])
726+ if joint_id is None :
727+ # still None, supress this and return the thread message
728+ logger .error ("Malformed thread message." )
729+ return linked_messages
730+
731+ for user in self .recipients :
732+ if user .dm_channel == message .channel :
733+ continue
734+ async for other_msg in user .history ():
735+ if either_direction :
736+ if other_msg .id == joint_id :
737+ linked_messages .append (other_msg )
738+ break
739+
740+ if not other_msg .embeds :
741+ continue
742+
743+ other_joint_id = get_joint_id (other_msg )
744+ if other_joint_id is not None and other_joint_id == joint_id :
745+ linked_messages .append (other_msg )
746+ break
747+ else :
748+ logger .error ("Linked message from recipient %s not found." , user )
749+
750+ return linked_messages
751+
732752 async def edit_dm_message (self , message : discord .Message , content : str ) -> None :
733753 try :
734- linked_message = await self .find_linked_message_from_dm (message )
754+ linked_messages = await self .find_linked_message_from_dm (message )
735755 except ValueError :
736756 logger .warning ("Failed to edit message." , exc_info = True )
737757 raise
738- embed = linked_message .embeds [0 ]
739- embed .add_field (name = "**Edited, former message:**" , value = embed .description )
740- embed .description = content
741- await asyncio .gather (self .bot .api .edit_message (message .id , content ), linked_message .edit (embed = embed ))
742758
743- async def note (self , message : discord .Message , persistent = False , thread_creation = False ) -> None :
759+ for msg in linked_messages :
760+ embed = msg .embeds [0 ]
761+ if isinstance (msg .channel , discord .TextChannel ):
762+ # just for thread channel, we put the old message in embed field
763+ embed .add_field (name = "**Edited, former message:**" , value = embed .description )
764+ embed .description = content
765+ await asyncio .gather (self .bot .api .edit_message (message .id , content ), msg .edit (embed = embed ))
766+
767+ async def note (
768+ self , message : discord .Message , persistent = False , thread_creation = False
769+ ) -> discord .Message :
744770 if not message .content and not message .attachments :
745771 raise MissingRequiredArgument (SimpleNamespace (name = "msg" ))
746772
@@ -758,7 +784,9 @@ async def note(self, message: discord.Message, persistent=False, thread_creation
758784
759785 return msg
760786
761- async def reply (self , message : discord .Message , anonymous : bool = False , plain : bool = False ) -> None :
787+ async def reply (
788+ self , message : discord .Message , anonymous : bool = False , plain : bool = False
789+ ) -> typing .Tuple [discord .Message , discord .Message ]:
762790 if not message .content and not message .attachments :
763791 raise MissingRequiredArgument (SimpleNamespace (name = "msg" ))
764792 if not any (g .get_member (self .id ) for g in self .bot .guilds ):
@@ -854,7 +882,8 @@ async def send(
854882 thread_creation : bool = False ,
855883 ) -> None :
856884
857- self .bot .loop .create_task (self ._restart_close_timer ()) # Start or restart thread auto close
885+ if not note and from_mod :
886+ self .bot .loop .create_task (self ._restart_close_timer ()) # Start or restart thread auto close
858887
859888 if self .close_task is not None :
860889 # cancel closing if a thread message is sent.
@@ -1208,9 +1237,13 @@ async def _find_from_channel(self, channel):
12081237 except discord .NotFound :
12091238 recipient = None
12101239
1211- other_recipients = match_other_recipients (channel .topic )
1212- for n , uid in enumerate (other_recipients ):
1213- other_recipients [n ] = self .bot .get_user (uid ) or await self .bot .fetch_user (uid )
1240+ other_recipients = []
1241+ for uid in match_other_recipients (channel .topic ):
1242+ try :
1243+ other_recipient = self .bot .get_user (uid ) or await self .bot .fetch_user (uid )
1244+ except discord .NotFound :
1245+ continue
1246+ other_recipients .append (other_recipient )
12141247
12151248 if recipient is None :
12161249 thread = Thread (self , user_id , channel , other_recipients )
0 commit comments