7
7
from django .db .models import Q
8
8
from django_stubs_ext import StrPromise
9
9
10
+ from zerver .lib .topic import get_last_message_for_user_in_topic
10
11
from zerver .lib .user_groups import get_recursive_group_members
11
12
from zerver .lib .users import get_inaccessible_user_ids
12
13
from zerver .models import NamedUserGroup , UserProfile
@@ -65,6 +66,19 @@ class PossibleMentions:
65
66
message_has_stream_wildcards : bool
66
67
67
68
69
+ @dataclass (frozen = True )
70
+ class ChannelTopicInfo :
71
+ channel_name : str
72
+ topic_name : str
73
+
74
+
75
+ @dataclass
76
+ class ChannelInfo :
77
+ channel_id : int
78
+ recipient_id : int
79
+ history_public_to_subscribers : bool
80
+
81
+
68
82
class MentionBackend :
69
83
# Be careful about reuse: MentionBackend contains caches which are
70
84
# designed to only have the lifespan of a sender user (typically a
@@ -76,7 +90,8 @@ class MentionBackend:
76
90
def __init__ (self , realm_id : int ) -> None :
77
91
self .realm_id = realm_id
78
92
self .user_cache : dict [tuple [int , str ], FullNameInfo ] = {}
79
- self .stream_cache : dict [str , int ] = {}
93
+ self .stream_cache : dict [str , ChannelInfo ] = {}
94
+ self .topic_cache : dict [ChannelTopicInfo , int ] = {}
80
95
81
96
def get_full_name_info_list (
82
97
self , user_filters : list [UserFilter ], message_sender : UserProfile | None
@@ -148,7 +163,7 @@ def get_stream_name_map(self, stream_names: set[str]) -> dict[str, int]:
148
163
149
164
for stream_name in stream_names :
150
165
if stream_name in self .stream_cache :
151
- result [stream_name ] = self .stream_cache [stream_name ]
166
+ result [stream_name ] = self .stream_cache [stream_name ]. channel_id
152
167
else :
153
168
unseen_stream_names .append (stream_name )
154
169
@@ -165,15 +180,58 @@ def get_stream_name_map(self, stream_names: set[str]) -> dict[str, int]:
165
180
.values (
166
181
"id" ,
167
182
"name" ,
183
+ "recipient_id" ,
184
+ "history_public_to_subscribers" ,
168
185
)
169
186
)
170
187
171
188
for row in rows :
172
- self .stream_cache [row ["name" ]] = row ["id" ]
189
+ self .stream_cache [row ["name" ]] = ChannelInfo (
190
+ row ["id" ], row ["recipient_id" ], row ["history_public_to_subscribers" ]
191
+ )
173
192
result [row ["name" ]] = row ["id" ]
174
193
175
194
return result
176
195
196
+ def get_topic_info_map (
197
+ self , channel_topic : set [ChannelTopicInfo ], message_sender : UserProfile | None
198
+ ) -> dict [ChannelTopicInfo , int ]:
199
+ if not channel_topic :
200
+ return {}
201
+
202
+ result : dict [ChannelTopicInfo , int ] = {}
203
+ unseen_channel_topic : list [ChannelTopicInfo ] = []
204
+
205
+ for channel_topic_object in channel_topic :
206
+ if channel_topic_object in self .topic_cache :
207
+ result [channel_topic_object ] = self .topic_cache [channel_topic_object ]
208
+ else :
209
+ unseen_channel_topic .append (channel_topic_object )
210
+
211
+ for channel_topic_object in unseen_channel_topic :
212
+ channel_info = self .stream_cache .get (channel_topic_object .channel_name )
213
+
214
+ assert channel_info is not None
215
+ recipient_id = channel_info .recipient_id
216
+ topic_name = channel_topic_object .topic_name
217
+ history_public_to_subscribers = channel_info .history_public_to_subscribers
218
+
219
+ topic_latest_message = get_last_message_for_user_in_topic (
220
+ self .realm_id ,
221
+ message_sender ,
222
+ recipient_id ,
223
+ topic_name ,
224
+ history_public_to_subscribers ,
225
+ )
226
+
227
+ if topic_latest_message is None :
228
+ continue
229
+
230
+ self .topic_cache [channel_topic_object ] = topic_latest_message
231
+ result [channel_topic_object ] = topic_latest_message
232
+
233
+ return result
234
+
177
235
178
236
def user_mention_matches_topic_wildcard (mention : str ) -> bool :
179
237
return mention in topic_wildcards
@@ -251,6 +309,7 @@ def __init__(
251
309
) -> None :
252
310
self .mention_backend = mention_backend
253
311
realm_id = mention_backend .realm_id
312
+ self .message_sender = message_sender
254
313
mentions = possible_mentions (content )
255
314
possible_mentions_info = get_possible_mentions_info (
256
315
mention_backend , mentions .mention_texts , message_sender
@@ -307,6 +366,11 @@ def get_group_members(self, user_group_id: int) -> list[int]:
307
366
def get_stream_name_map (self , stream_names : set [str ]) -> dict [str , int ]:
308
367
return self .mention_backend .get_stream_name_map (stream_names )
309
368
369
+ def get_topic_info_map (
370
+ self , channel_topic_names : set [ChannelTopicInfo ]
371
+ ) -> dict [ChannelTopicInfo , int ]:
372
+ return self .mention_backend .get_topic_info_map (channel_topic_names , self .message_sender )
373
+
310
374
311
375
def silent_mention_syntax_for_user (user_profile : UserProfile ) -> str :
312
376
return f"@_**{ user_profile .full_name } |{ user_profile .id } **"
0 commit comments