Coverage for app / backend / src / tests / test_conversations.py: 100%
1228 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-03 06:18 +0000
« prev ^ index » next coverage.py v7.13.2, created at 2026-02-03 06:18 +0000
1from datetime import timedelta
3import grpc
4import pytest
5from google.protobuf import wrappers_pb2
6from sqlalchemy import select
8from couchers.db import session_scope
9from couchers.jobs.worker import process_job
10from couchers.models import (
11 GroupChatRole,
12 GroupChatSubscription,
13 Notification,
14 NotificationDelivery,
15 NotificationDeliveryType,
16 NotificationTopicAction,
17 RateLimitAction,
18)
19from couchers.proto import api_pb2, conversations_pb2, notification_data_pb2, notifications_pb2
20from couchers.rate_limits.definitions import RATE_LIMIT_DEFINITIONS, RATE_LIMIT_HOURS
21from couchers.utils import Duration_from_timedelta, now, to_aware_datetime
22from tests.fixtures.db import generate_user, make_friends, make_user_block, make_user_invisible
23from tests.fixtures.misc import email_fields, mock_notification_email
24from tests.fixtures.sessions import api_session, conversations_session, notifications_session
27@pytest.fixture(autouse=True)
28def _(testconfig):
29 pass
32def test_list_group_chats(db, moderator):
33 user1, token1 = generate_user()
34 user2, token2 = generate_user()
35 user3, token3 = generate_user()
37 make_friends(user2, user1)
38 make_friends(user1, user3)
40 with conversations_session(token1) as c:
41 # no threads initially
42 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
43 assert len(res.group_chats) == 0
45 # create some group chats with messages
46 res = c.CreateGroupChat(
47 conversations_pb2.CreateGroupChatReq(
48 recipient_user_ids=[user2.id], title=wrappers_pb2.StringValue(value="Test title")
49 )
50 )
51 group_chat1_id = res.group_chat_id
52 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message 1"))
53 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message 2"))
54 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
55 group_chat2_id = res.group_chat_id
56 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test group message 1"))
57 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test group message 2"))
59 moderator.approve_group_chat(group_chat1_id)
60 moderator.approve_group_chat(group_chat2_id)
62 with conversations_session(token1) as c:
63 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
64 assert len(res.group_chats) == 2
65 assert res.no_more
67 with conversations_session(token2) as c:
68 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
69 assert len(res.group_chats) == 2
70 assert res.no_more
72 with conversations_session(token3) as c:
73 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
74 assert len(res.group_chats) == 1
75 assert res.no_more
77 # Test archive filtering: archive group_chat1 for user1
78 with conversations_session(token1) as c:
79 res = c.SetGroupChatArchiveStatus(
80 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=group_chat1_id, is_archived=True)
81 )
82 assert res.group_chat_id == group_chat1_id
83 assert res.is_archived
85 with conversations_session(token1) as c:
86 # Without filter, returns all chats
87 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
88 assert len(res.group_chats) == 2
90 # only_archived=False returns non-archived chats only
91 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False))
92 assert len(res.group_chats) == 1
94 # only_archived=True returns archived chats only
95 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True))
96 assert len(res.group_chats) == 1
98 # user2 should still see both as non-archived (archive is per-user)
99 with conversations_session(token2) as c:
100 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False))
101 assert len(res.group_chats) == 2
103 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True))
104 assert len(res.group_chats) == 0
107def test_list_empty_group_chats(db, moderator):
108 user1, token1 = generate_user()
109 user2, token2 = generate_user()
110 user3, token3 = generate_user()
112 make_friends(user1, user3)
113 make_friends(user2, user1)
114 make_friends(user2, user3)
116 with conversations_session(token1) as c:
117 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
118 assert len(res.group_chats) == 0
120 res1 = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
121 res2 = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
123 moderator.approve_group_chat(res1.group_chat_id)
124 moderator.approve_group_chat(res2.group_chat_id)
126 with conversations_session(token1) as c:
127 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
128 assert len(res.group_chats) == 2
129 assert res.no_more
131 with conversations_session(token2) as c:
132 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
133 assert len(res.group_chats) == 2
134 assert res.no_more
136 res3 = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id]))
137 moderator.approve_group_chat(res3.group_chat_id)
139 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
140 assert len(res.group_chats) == 3
141 assert res.no_more
143 with conversations_session(token3) as c:
144 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
145 assert len(res.group_chats) == 2
146 assert res.no_more
149def test_list_group_chats_ordering(db, moderator):
150 # user is member of 5 group chats, order them correctly
151 user, token = generate_user()
152 user2, token2 = generate_user()
153 user3, token3 = generate_user()
154 user4, token4 = generate_user()
156 make_friends(user2, user)
157 make_friends(user2, user3)
158 make_friends(user2, user4)
159 make_friends(user3, user)
160 make_friends(user3, user4)
161 make_friends(user, user4)
163 chat_ids = []
165 with conversations_session(token2) as c:
166 res = c.CreateGroupChat(
167 conversations_pb2.CreateGroupChatReq(
168 recipient_user_ids=[user.id], title=wrappers_pb2.StringValue(value="Chat 0")
169 )
170 )
171 chat_ids.append(res.group_chat_id)
172 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
173 res = c.CreateGroupChat(
174 conversations_pb2.CreateGroupChatReq(
175 recipient_user_ids=[user.id, user3.id], title=wrappers_pb2.StringValue(value="Chat 1")
176 )
177 )
178 chat_ids.append(res.group_chat_id)
179 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
180 res = c.CreateGroupChat(
181 conversations_pb2.CreateGroupChatReq(
182 recipient_user_ids=[user.id, user3.id], title=wrappers_pb2.StringValue(value="Chat 2")
183 )
184 )
185 chat_ids.append(res.group_chat_id)
186 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
188 with conversations_session(token3) as c:
189 res = c.CreateGroupChat(
190 conversations_pb2.CreateGroupChatReq(
191 recipient_user_ids=[user.id, user2.id, user4.id], title=wrappers_pb2.StringValue(value="Chat 3")
192 )
193 )
194 chat_ids.append(res.group_chat_id)
195 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
197 for chat_id in chat_ids:
198 moderator.approve_group_chat(chat_id)
200 with conversations_session(token) as c:
201 res = c.CreateGroupChat(
202 conversations_pb2.CreateGroupChatReq(
203 recipient_user_ids=[user2.id, user3.id, user4.id], title=wrappers_pb2.StringValue(value="Chat 4")
204 )
205 )
206 moderator.approve_group_chat(res.group_chat_id)
207 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
208 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
209 assert len(res.group_chats) == 5
210 assert res.group_chats[0].title == "Chat 4"
211 assert res.group_chats[1].title == "Chat 3"
212 assert res.group_chats[2].title == "Chat 2"
213 assert res.group_chats[3].title == "Chat 1"
214 assert res.group_chats[4].title == "Chat 0"
216 c.SendMessage(
217 conversations_pb2.SendMessageReq(group_chat_id=res.group_chats[3].group_chat_id, text="Test message 2a")
218 )
219 c.SendMessage(
220 conversations_pb2.SendMessageReq(group_chat_id=res.group_chats[2].group_chat_id, text="Test message 2b")
221 )
223 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
224 assert len(res.group_chats) == 5
225 assert res.group_chats[0].title == "Chat 2"
226 assert res.group_chats[0].latest_message.text.text == "Test message 2b"
227 assert res.group_chats[1].title == "Chat 1"
228 assert res.group_chats[1].latest_message.text.text == "Test message 2a"
229 assert res.group_chats[2].title == "Chat 4"
230 assert res.group_chats[3].title == "Chat 3"
231 assert res.group_chats[4].title == "Chat 0"
234def test_list_group_chats_ordering_after_left(db, moderator):
235 # user is member to 4 group chats, and has left one.
236 # The one user left has the most recent message, but user left before then,
237 # this should display as e.g. 3rd most recent depending on last message when they were in the chat
238 user, token = generate_user()
239 user2, token2 = generate_user()
240 user3, token3 = generate_user()
241 user4, token4 = generate_user()
243 make_friends(user2, user)
244 make_friends(user2, user3)
245 make_friends(user2, user4)
246 make_friends(user3, user)
247 make_friends(user3, user4)
248 make_friends(user, user4)
250 chat_ids = []
252 with conversations_session(token2) as c:
253 res = c.CreateGroupChat(
254 conversations_pb2.CreateGroupChatReq(
255 recipient_user_ids=[user.id], title=wrappers_pb2.StringValue(value="Chat 0")
256 )
257 )
258 chat_ids.append(res.group_chat_id)
259 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
260 res = c.CreateGroupChat(
261 conversations_pb2.CreateGroupChatReq(
262 recipient_user_ids=[user.id, user3.id], title=wrappers_pb2.StringValue(value="Left Chat 1")
263 )
264 )
265 left_chat_id = res.group_chat_id
266 chat_ids.append(left_chat_id)
267 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=left_chat_id, text="Test message"))
268 res = c.CreateGroupChat(
269 conversations_pb2.CreateGroupChatReq(
270 recipient_user_ids=[user.id, user3.id], title=wrappers_pb2.StringValue(value="Chat 2")
271 )
272 )
273 chat2_id = res.group_chat_id
274 chat_ids.append(chat2_id)
275 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=chat2_id, text="Test message"))
277 with conversations_session(token3) as c:
278 res = c.CreateGroupChat(
279 conversations_pb2.CreateGroupChatReq(
280 recipient_user_ids=[user.id, user2.id, user4.id], title=wrappers_pb2.StringValue(value="Chat 3")
281 )
282 )
283 chat_ids.append(res.group_chat_id)
284 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
286 for chat_id in chat_ids:
287 moderator.approve_group_chat(chat_id)
289 with conversations_session(token) as c:
290 res = c.CreateGroupChat(
291 conversations_pb2.CreateGroupChatReq(
292 recipient_user_ids=[user2.id, user3.id, user4.id], title=wrappers_pb2.StringValue(value="Chat 4")
293 )
294 )
295 moderator.approve_group_chat(res.group_chat_id)
296 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
298 # leave chat
299 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=left_chat_id))
301 with conversations_session(token3) as c:
302 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=chat2_id, text="Test message"))
303 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=left_chat_id, text="Test message"))
305 with conversations_session(token2) as c:
306 # other user sends a message to that chat
307 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=left_chat_id, text="Another test message"))
308 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
309 assert len(res.group_chats) == 5
310 assert res.group_chats[0].title == "Left Chat 1"
311 assert res.group_chats[1].title == "Chat 2"
312 assert res.group_chats[2].title == "Chat 4"
313 assert res.group_chats[3].title == "Chat 3"
314 assert res.group_chats[4].title == "Chat 0"
316 with conversations_session(token) as c:
317 # we can't see the new message since we left before it was sent
318 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
319 assert len(res.group_chats) == 5
320 assert res.group_chats[0].title == "Chat 2"
321 assert res.group_chats[1].title == "Left Chat 1"
322 assert res.group_chats[2].title == "Chat 4"
323 assert res.group_chats[3].title == "Chat 3"
324 assert res.group_chats[4].title == "Chat 0"
327def test_get_group_chat_messages(db):
328 user1, token1 = generate_user()
329 user2, token2 = generate_user()
330 user3, token3 = generate_user()
332 make_friends(user1, user2)
334 with conversations_session(token1) as c:
335 # create some threads with messages
336 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
337 group_chat_id = res.group_chat_id
338 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message 1"))
339 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message 2"))
341 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
342 # created + 2 normal
343 assert len(res.messages) == 3
344 assert res.no_more
346 assert res.messages[0].text.text == "Test message 2"
347 assert res.messages[1].text.text == "Test message 1"
348 assert res.messages[2].WhichOneof("content") == "chat_created"
350 # test that another user can't access the thread
351 with conversations_session(token3) as c:
352 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
353 assert len(res.messages) == 0
356def test_get_group_chat_messages_pagination(db, moderator):
357 user1, token1 = generate_user()
358 user2, token2 = generate_user()
359 make_friends(user1, user2)
361 with conversations_session(token1) as c:
362 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
363 group_chat_id = res.group_chat_id
364 for i in range(30):
365 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text=str(i)))
367 moderator.approve_group_chat(group_chat_id)
369 with conversations_session(token2) as c:
370 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
371 # pagination
372 assert len(res.messages) == 20
373 assert res.messages[0].text.text == "29"
374 assert res.messages[19].text.text == "10"
375 assert not res.no_more
376 res = c.GetGroupChatMessages(
377 conversations_pb2.GetGroupChatMessagesReq(
378 group_chat_id=group_chat_id, last_message_id=res.messages[19].message_id
379 )
380 )
381 assert len(res.messages) == 11
382 assert res.messages[0].text.text == "9"
383 assert res.messages[9].text.text == "0"
384 assert res.no_more
387def test_get_group_chat_messages_joined_left(db, moderator):
388 user1, token1 = generate_user()
389 user2, token2 = generate_user()
390 user3, token3 = generate_user()
391 user4, token4 = generate_user()
392 make_friends(user1, user2)
393 make_friends(user1, user3)
394 make_friends(user1, user4)
396 with conversations_session(token1) as c:
397 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user4.id]))
398 group_chat_id = res.group_chat_id
399 moderator.approve_group_chat(group_chat_id)
401 for i in range(10):
402 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text=str(i)))
404 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id))
406 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="10"))
408 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
410 # created + 10 normal + invited + normal
411 assert len(res.messages) == 13
413 with conversations_session(token3) as c:
414 # can only see last message after invited
415 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
416 # joined + normal
417 assert len(res.messages) == 2
418 assert res.messages[0].text.text == "10"
420 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
422 with conversations_session(token1) as c:
423 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="11"))
424 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="12"))
426 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id))
428 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="13"))
429 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="14"))
431 with conversations_session(token3) as c:
432 # can only see last message after invited
433 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
434 # joined + normal + left + invite + 2 normal
435 assert len(res.messages) == 6
436 assert res.messages[0].text.text == "14"
437 assert res.messages[1].text.text == "13"
438 assert res.messages[2].WhichOneof("content") == "user_invited"
439 assert res.messages[3].WhichOneof("content") == "user_left"
440 assert res.messages[4].text.text == "10"
441 assert res.messages[5].WhichOneof("content") == "user_invited"
444def test_get_group_chat_info(db):
445 user1, token1 = generate_user()
446 user2, token2 = generate_user()
447 user3, token3 = generate_user()
449 make_friends(user1, user2)
450 make_friends(user3, user1)
452 with conversations_session(token1) as c:
453 # create some threads with messages
454 res = c.CreateGroupChat(
455 conversations_pb2.CreateGroupChatReq(
456 recipient_user_ids=[user2.id], title=wrappers_pb2.StringValue(value="Test title")
457 )
458 )
459 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message 1"))
460 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message 2"))
461 group_chat1_id = res.group_chat_id
462 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
463 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test group message 1"))
464 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test group message 2"))
465 group_chat2_id = res.group_chat_id
467 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat1_id))
468 assert res.title == "Test title"
469 assert user2.id in res.member_user_ids
470 assert user1.id in res.admin_user_ids
471 assert to_aware_datetime(res.created) <= now()
472 assert res.only_admins_invite
473 assert res.is_dm
474 assert not res.is_archived
476 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat2_id))
477 assert not res.title
478 assert user2.id in res.member_user_ids
479 assert user3.id in res.member_user_ids
480 assert user1.id in res.admin_user_ids
481 assert to_aware_datetime(res.created) <= now()
482 assert res.only_admins_invite
483 assert not res.is_dm
484 assert not res.is_archived
487def test_get_group_chat_info_denied(db):
488 user1, token1 = generate_user()
489 user2, token2 = generate_user()
490 user3, token3 = generate_user()
491 user4, token4 = generate_user()
493 make_friends(user1, user2)
494 make_friends(user3, user1)
496 with conversations_session(token1) as c:
497 # create a group chat with messages
498 res = c.CreateGroupChat(
499 conversations_pb2.CreateGroupChatReq(
500 recipient_user_ids=[user2.id, user3.id], title=wrappers_pb2.StringValue(value="Test title")
501 )
502 )
503 group_chat_id = res.group_chat_id
504 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
506 with conversations_session(token4) as c:
507 with pytest.raises(grpc.RpcError) as e:
508 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
509 assert e.value.code() == grpc.StatusCode.NOT_FOUND
512def test_get_group_chat_info_left(db, moderator):
513 user1, token1 = generate_user()
514 user2, token2 = generate_user()
515 user3, token3 = generate_user()
516 user4, token4 = generate_user()
518 make_friends(user1, user2)
519 make_friends(user3, user1)
520 make_friends(user1, user4)
522 with conversations_session(token1) as c:
523 # create a group chat with messages
524 res = c.CreateGroupChat(
525 conversations_pb2.CreateGroupChatReq(
526 recipient_user_ids=[user2.id, user3.id], title=wrappers_pb2.StringValue(value="Test title")
527 )
528 )
529 group_chat_id = res.group_chat_id
530 moderator.approve_group_chat(group_chat_id)
531 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
533 with conversations_session(token3) as c:
534 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
536 with conversations_session(token1) as c:
537 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user4.id))
539 with conversations_session(token3) as c:
540 # this user left when user4 wasn't a member,
541 # so the returned members should be user1, user2, and user3 only
542 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
543 assert len(res.member_user_ids) == 3
544 assert user1.id in res.member_user_ids
545 assert user2.id in res.member_user_ids
546 assert user3.id in res.member_user_ids
549def test_remove_group_chat_user(db):
550 # create 3 uses and connect them
551 user1, token1 = generate_user()
552 user2, token2 = generate_user()
553 user3, token3 = generate_user()
554 make_friends(user1, user2)
555 make_friends(user1, user3)
557 # using user token, create a Conversations API for testing
558 with conversations_session(token1) as c:
559 # create a group chat
560 res = c.CreateGroupChat(
561 conversations_pb2.CreateGroupChatReq(
562 recipient_user_ids=[user2.id, user3.id], title=wrappers_pb2.StringValue(value="Test title")
563 )
564 )
565 group_chat_id = res.group_chat_id
567 # remove a user from group
568 c.RemoveGroupChatUser(conversations_pb2.RemoveGroupChatUserReq(group_chat_id=group_chat_id, user_id=user2.id))
569 assert user3.id in res.member_user_ids # other users are still in the group
571 # can't remove the same user twice
572 with pytest.raises(grpc.RpcError) as e:
573 c.RemoveGroupChatUser(
574 conversations_pb2.RemoveGroupChatUserReq(group_chat_id=group_chat_id, user_id=user2.id)
575 )
576 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
579def test_edit_group_chat(db, moderator):
580 user1, token1 = generate_user()
581 user2, token2 = generate_user()
582 user3, token3 = generate_user()
583 make_friends(user1, user2)
585 with conversations_session(token1) as c:
586 # create some threads with messages
587 res = c.CreateGroupChat(
588 conversations_pb2.CreateGroupChatReq(
589 recipient_user_ids=[user2.id], title=wrappers_pb2.StringValue(value="Test title")
590 )
591 )
592 group_chat_id = res.group_chat_id
593 moderator.approve_group_chat(group_chat_id)
595 c.EditGroupChat(
596 conversations_pb2.EditGroupChatReq(
597 group_chat_id=group_chat_id,
598 title=wrappers_pb2.StringValue(value="Modified title"),
599 only_admins_invite=wrappers_pb2.BoolValue(value=False),
600 )
601 )
602 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
603 assert res.title == "Modified title"
604 assert not res.only_admins_invite
606 # make sure non-admin is not allowed to modify
607 with conversations_session(token2) as c:
608 with pytest.raises(grpc.RpcError) as e:
609 c.EditGroupChat(
610 conversations_pb2.EditGroupChatReq(
611 group_chat_id=group_chat_id,
612 title=wrappers_pb2.StringValue(value="Other title"),
613 only_admins_invite=wrappers_pb2.BoolValue(value=True),
614 )
615 )
616 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED
618 # make sure non-recipient is not allowed to modify
619 with conversations_session(token3) as c:
620 with pytest.raises(grpc.RpcError) as e:
621 c.EditGroupChat(
622 conversations_pb2.EditGroupChatReq(
623 group_chat_id=group_chat_id,
624 title=wrappers_pb2.StringValue(value="Other title"),
625 only_admins_invite=wrappers_pb2.BoolValue(value=True),
626 )
627 )
628 assert e.value.code() == grpc.StatusCode.NOT_FOUND
631def test_make_remove_group_chat_admin(db, moderator):
632 user1, token1 = generate_user()
633 user2, token2 = generate_user()
634 user3, token3 = generate_user()
636 make_friends(user1, user2)
637 make_friends(user1, user3)
638 make_friends(user2, user3)
640 with conversations_session(token1) as c:
641 # create some threads with messages
642 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
643 group_chat_id = res.group_chat_id
644 moderator.approve_group_chat(group_chat_id)
646 # shouldn't be able to remove only admin
647 with pytest.raises(grpc.RpcError) as e:
648 c.RemoveGroupChatAdmin(
649 conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=group_chat_id, user_id=user1.id)
650 )
651 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
652 assert e.value.details() == "You can't remove the last admin."
654 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=group_chat_id, user_id=user2.id))
656 # shouldn't be able to make admin again
657 with pytest.raises(grpc.RpcError) as e:
658 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=group_chat_id, user_id=user2.id))
659 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
660 assert e.value.details() == "That user is already an admin."
662 with conversations_session(token2) as c:
663 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
664 assert user1.id in res.admin_user_ids
665 assert user2.id in res.admin_user_ids
667 with conversations_session(token1) as c:
668 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=group_chat_id, user_id=user2.id))
670 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
671 assert user1.id in res.admin_user_ids
672 assert user2.id not in res.admin_user_ids
674 with conversations_session(token2) as c:
675 # shouldn't be able to make admin if not admin
676 with pytest.raises(grpc.RpcError) as e:
677 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=group_chat_id, user_id=user3.id))
678 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED
681def test_send_message(db):
682 user1, token1 = generate_user()
683 user2, token2 = generate_user()
684 user3, token3 = generate_user()
685 make_friends(user1, user2)
686 make_friends(user1, user3)
688 with conversations_session(token1) as c:
689 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
690 group_chat_id = res.group_chat_id
691 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
692 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
693 assert res.messages[0].text.text == "Test message 1"
694 assert to_aware_datetime(res.messages[0].time) <= now()
695 assert res.messages[0].author_user_id == user1.id
697 # can't send message if not in chat
698 with conversations_session(token3) as c:
699 with pytest.raises(grpc.RpcError) as e:
700 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 2"))
701 assert e.value.code() == grpc.StatusCode.NOT_FOUND
703 make_user_block(user2, user1)
704 with conversations_session(token1) as c:
705 with pytest.raises(grpc.RpcError) as e:
706 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Message after block"))
707 assert e.value.details() == "You can't send a message in this chat."
710def test_send_direct_message(db, moderator):
711 user1, token1 = generate_user(complete_profile=True)
712 user2, token2 = generate_user(complete_profile=True)
714 make_friends(user1, user2)
716 message1 = "Hello, user2!"
717 message2 = "One more message."
719 with conversations_session(token1) as c1:
720 # Send a DM from user1 to user2
721 res = c1.SendDirectMessage(conversations_pb2.SendDirectMessageReq(recipient_user_id=user2.id, text=message1))
722 moderator.approve_group_chat(res.group_chat_id)
724 c1.SendDirectMessage(conversations_pb2.SendDirectMessageReq(recipient_user_id=user2.id, text=message2))
726 with conversations_session(token2) as c2:
727 # Fetch the chat by ID returned from SendDirectMessage
728 chat = c2.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=res.group_chat_id))
730 assert chat.is_dm
731 group_chat_id = chat.group_chat_id
733 # Verify that the messages was received
734 messages = c2.GetGroupChatMessages(
735 conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id)
736 ).messages
738 assert len(messages) == 2
739 assert messages[0].text.text == message2
740 assert messages[1].text.text == message1
741 assert messages[0].author_user_id == user1.id
744def test_excessive_chat_initiations_are_reported(db):
745 """Test that excessive chat initiations are first reported in a warning email and finally lead blocking of further contacting other users."""
746 user, token = generate_user()
747 rate_limit_definition = RATE_LIMIT_DEFINITIONS[RateLimitAction.chat_initiation]
748 with conversations_session(token) as c:
749 # Test warning email
750 with mock_notification_email() as mock_email:
751 for _ in range(rate_limit_definition.warning_limit):
752 recipient_user, _ = generate_user()
753 _ = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[recipient_user.id]))
755 assert mock_email.call_count == 0
756 recipient_user, _ = generate_user()
757 _ = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[recipient_user.id]))
759 assert mock_email.call_count == 1
760 email = email_fields(mock_email).plain
761 assert email.startswith(
762 f"User {user.username} has sent {rate_limit_definition.warning_limit} chat initiations in the past {RATE_LIMIT_HOURS} hours."
763 )
765 # Test new chat initiations fail after exceeding CHAT_INITIATION_HARD_LIMIT
766 with mock_notification_email() as mock_email:
767 for _ in range(rate_limit_definition.hard_limit - rate_limit_definition.warning_limit - 1):
768 recipient_user, _ = generate_user()
769 _ = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[recipient_user.id]))
771 assert mock_email.call_count == 0
772 recipient_user, _ = generate_user()
773 with pytest.raises(grpc.RpcError) as exc_info:
774 _ = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[recipient_user.id]))
775 assert exc_info.value.code() == grpc.StatusCode.RESOURCE_EXHAUSTED
776 assert (
777 exc_info.value.details()
778 == "You have messaged a lot of users in the past 24 hours. To avoid spam, you can't contact any more users for now."
779 )
781 assert mock_email.call_count == 1
782 email = email_fields(mock_email).plain
783 assert email.startswith(
784 f"User {user.username} has sent {rate_limit_definition.hard_limit} chat initiations in the past {RATE_LIMIT_HOURS} hours."
785 )
786 assert "The user has been blocked from sending further chat initiations for now." in email
789def test_leave_invite_to_group_chat(db, moderator):
790 user1, token1 = generate_user()
791 user2, token2 = generate_user()
792 user3, token3 = generate_user()
793 user4, token4 = generate_user()
794 user5, token5 = generate_user()
795 user6, token6 = generate_user(delete_user=True)
796 user7, token7 = generate_user()
797 user8, token8 = generate_user()
799 make_friends(user1, user2)
800 make_friends(user1, user3)
801 make_friends(user1, user5)
802 make_friends(user1, user7)
803 make_friends(user1, user8)
804 make_friends(user2, user3)
805 make_friends(user4, user3)
806 make_user_block(user1, user7)
807 make_user_block(user8, user1)
809 with conversations_session(token1) as c:
810 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user5.id]))
811 group_chat_id = res.group_chat_id
812 moderator.approve_group_chat(group_chat_id)
813 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
815 # other user not in chat
816 with conversations_session(token3) as c:
817 with pytest.raises(grpc.RpcError) as e:
818 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
819 assert e.value.code() == grpc.StatusCode.NOT_FOUND
820 with pytest.raises(grpc.RpcError) as e:
821 res = c.InviteToGroupChat(
822 conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user4.id)
823 )
824 assert e.value.code() == grpc.StatusCode.NOT_FOUND
825 with pytest.raises(grpc.RpcError) as e:
826 res = c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
827 assert e.value.code() == grpc.StatusCode.NOT_FOUND
829 with conversations_session(token2) as c:
830 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
831 assert user3.id not in res.member_user_ids
833 # only_admins_invite defaults to true so shouldn't be able to invite
834 with pytest.raises(grpc.RpcError) as e:
835 res = c.InviteToGroupChat(
836 conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id)
837 )
838 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED
839 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
841 with conversations_session(token1) as c:
842 # invite invisible user fails
843 with pytest.raises(grpc.RpcError) as e:
844 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user6.id))
845 assert e.value.code() == grpc.StatusCode.NOT_FOUND
846 assert e.value.details() == "Couldn't find that user."
847 # invite fake user fails
848 with pytest.raises(grpc.RpcError) as e:
849 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=999))
850 assert e.value.code() == grpc.StatusCode.NOT_FOUND
851 assert e.value.details() == "Couldn't find that user."
852 # invite blocked user fails
853 with pytest.raises(grpc.RpcError) as e:
854 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user7.id))
855 assert e.value.code() == grpc.StatusCode.NOT_FOUND
856 assert e.value.details() == "Couldn't find that user."
857 # invite blocking user fails
858 with pytest.raises(grpc.RpcError) as e:
859 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user8.id))
860 assert e.value.code() == grpc.StatusCode.NOT_FOUND
861 assert e.value.details() == "Couldn't find that user."
863 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id))
864 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
865 assert user1.id in res.member_user_ids
866 assert user5.id in res.member_user_ids
867 assert user3.id in res.member_user_ids
869 # test non-admin inviting
870 c.EditGroupChat(
871 conversations_pb2.EditGroupChatReq(
872 group_chat_id=group_chat_id, only_admins_invite=wrappers_pb2.BoolValue(value=False)
873 )
874 )
876 with conversations_session(token3) as c:
877 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user2.id))
878 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
879 assert user2.id in res.member_user_ids
882def test_group_chats_with_messages_before_join(db, moderator):
883 """
884 If user 1 and 2 have a group chat and send messages, then add user 3; user 3
885 should still see the group chat!
886 """
887 user1, token1 = generate_user()
888 user2, token2 = generate_user()
889 user3, token3 = generate_user()
890 user4, token4 = generate_user()
892 make_friends(user1, user2)
893 make_friends(user1, user3)
894 make_friends(user2, user3)
895 make_friends(user1, user4)
897 with conversations_session(token1) as c:
898 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user4.id]))
899 group_chat_id = res.group_chat_id
900 moderator.approve_group_chat(group_chat_id)
901 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
903 with conversations_session(token2) as c:
904 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 2"))
906 with conversations_session(token1) as c:
907 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 3"))
909 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id))
911 with conversations_session(token3) as c:
912 # should work
913 c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
915 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
916 assert len(res.group_chats) == 1
919def test_invite_to_dm(db):
920 user1, token1 = generate_user()
921 user2, token2 = generate_user()
922 user3, token3 = generate_user()
924 make_friends(user1, user2)
925 make_friends(user1, user3)
926 make_friends(user2, user3)
928 with conversations_session(token1) as c:
929 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
930 group_chat_id = res.group_chat_id
931 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
933 # dm, shou;dn't be able to invite someone else
934 with pytest.raises(grpc.RpcError) as e:
935 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id))
936 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
937 assert e.value.details() == "You can't invite other users to a direct message."
940def test_sole_admin_leaves(db, moderator):
941 user1, token1 = generate_user()
942 user2, token2 = generate_user()
943 user3, token3 = generate_user()
945 make_friends(user1, user2)
946 make_friends(user1, user3)
947 make_friends(user2, user3)
949 with conversations_session(token1) as c:
950 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
951 group_chat_id = res.group_chat_id
952 moderator.approve_group_chat(group_chat_id)
953 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
955 # sole admin can't leave group chat
956 with pytest.raises(grpc.RpcError) as e:
957 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
958 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
959 assert e.value.details() == "The last admin can't leave a group chat."
961 with conversations_session(token2) as c:
962 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
964 with conversations_session(token3) as c:
965 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
967 # sole admin can leave when last in chat
968 with conversations_session(token1) as c:
969 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
972def test_search_messages(db, moderator):
973 user1, token1 = generate_user()
974 user2, token2 = generate_user()
975 user3, token3 = generate_user()
977 make_friends(user1, user2)
978 make_friends(user1, user3)
980 with conversations_session(token1) as c:
981 # create some threads with messages
982 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
983 gc1_id = res.group_chat_id
984 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gc1_id, text="Test message 1"))
985 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gc1_id, text="Test message 2"))
986 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
987 gc2_id = res.group_chat_id
988 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gc2_id, text="Test group message 3"))
989 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gc2_id, text="Test group message 4"))
991 # Approve group chats so they appear in search results
992 moderator.approve_group_chat(gc1_id)
993 moderator.approve_group_chat(gc2_id)
995 with conversations_session(token1) as c:
996 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="message "))
997 assert len(res.results) == 4
998 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="group "))
999 assert len(res.results) == 2
1000 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="message 5"))
1001 assert len(res.results) == 0
1003 # outside user doesn't get results
1004 with conversations_session(token3) as c:
1005 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="Test message"))
1006 assert len(res.results) == 0
1009def test_search_messages_left_joined(db, moderator):
1010 user1, token1 = generate_user()
1011 user2, token2 = generate_user()
1012 user3, token3 = generate_user()
1013 user4, token4 = generate_user()
1014 make_friends(user1, user2)
1015 make_friends(user1, user3)
1016 make_friends(user1, user4)
1018 with conversations_session(token1) as c:
1019 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user4.id]))
1020 group_chat_id = res.group_chat_id
1021 moderator.approve_group_chat(group_chat_id)
1022 for i in range(10):
1023 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message " + str(i)))
1025 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id))
1026 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 10"))
1027 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="Test message"))
1029 assert len(res.results) == 11
1031 with conversations_session(token3) as c:
1032 # can only see last message after invited
1033 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="Test message"))
1035 assert len(res.results) == 1
1036 assert res.results[0].message.text.text == "Test message 10"
1038 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
1040 with conversations_session(token1) as c:
1041 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 11"))
1042 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 12"))
1043 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id))
1044 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 13"))
1045 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 14"))
1047 with conversations_session(token3) as c:
1048 # can only see last message after invited
1049 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="Test message"))
1050 assert len(res.results) == 3
1051 assert res.results[0].message.text.text == "Test message 14"
1052 assert res.results[1].message.text.text == "Test message 13"
1053 assert res.results[2].message.text.text == "Test message 10"
1056def test_admin_behaviour(db, moderator):
1057 user1, token1 = generate_user()
1058 user2, token2 = generate_user()
1059 user3, token3 = generate_user()
1061 make_friends(user1, user2)
1062 make_friends(user1, user3)
1063 make_friends(user2, user3)
1065 with conversations_session(token1) as c:
1066 gcid = c.CreateGroupChat(
1067 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])
1068 ).group_chat_id
1069 moderator.approve_group_chat(gcid)
1070 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user2.id))
1071 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1072 assert len(res.admin_user_ids) == 2
1073 assert user1.id in res.admin_user_ids
1074 assert user2.id in res.admin_user_ids
1076 with conversations_session(token3) as c:
1077 with pytest.raises(grpc.RpcError) as e:
1078 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id))
1079 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED
1080 with pytest.raises(grpc.RpcError) as e:
1081 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user1.id))
1082 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED
1083 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1084 assert len(res.admin_user_ids) == 2
1085 assert user1.id in res.admin_user_ids
1086 assert user2.id in res.admin_user_ids
1088 with conversations_session(token2) as c:
1089 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id))
1090 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1091 assert len(res.admin_user_ids) == 3
1092 assert user1.id in res.admin_user_ids
1093 assert user2.id in res.admin_user_ids
1094 assert user3.id in res.admin_user_ids
1096 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user1.id))
1097 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1098 assert len(res.admin_user_ids) == 2
1099 assert user2.id in res.admin_user_ids
1100 assert user3.id in res.admin_user_ids
1102 with conversations_session(token1) as c:
1103 with pytest.raises(grpc.RpcError):
1104 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user1.id))
1105 with pytest.raises(grpc.RpcError):
1106 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id))
1107 with pytest.raises(grpc.RpcError):
1108 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user2.id))
1109 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1110 assert len(res.admin_user_ids) == 2
1111 assert user2.id in res.admin_user_ids
1112 assert user3.id in res.admin_user_ids
1114 with conversations_session(token2) as c:
1115 # can demote self if there are other admins
1116 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user2.id))
1117 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1118 assert len(res.admin_user_ids) == 1
1119 assert user3.id in res.admin_user_ids
1121 with conversations_session(token3) as c:
1122 with pytest.raises(grpc.RpcError) as e:
1123 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id))
1124 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1125 assert e.value.details() == "You can't remove the last admin."
1126 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1127 assert len(res.admin_user_ids) == 1
1128 assert user3.id in res.admin_user_ids
1130 # last admin can't leave
1131 with pytest.raises(grpc.RpcError) as e:
1132 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid))
1133 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1134 assert e.value.details() == "The last admin can't leave a group chat."
1136 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user1.id))
1138 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid))
1140 with conversations_session(token2) as c:
1141 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid))
1143 # last participant must be admin but can leave to orphan chat
1144 with conversations_session(token1) as c:
1145 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid))
1148def test_add_remove_admin_failures(db):
1149 user1, token1 = generate_user()
1150 user2, token2 = generate_user()
1151 user3, token3 = generate_user()
1152 user4, token4 = generate_user()
1153 user5, token5 = generate_user()
1155 make_friends(user1, user2)
1156 make_friends(user1, user3)
1157 make_friends(user1, user4)
1158 make_friends(user1, user5)
1160 with conversations_session(token1) as c:
1161 gcid = c.CreateGroupChat(
1162 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id, user4.id, user5.id])
1163 ).group_chat_id
1165 make_user_invisible(user3.id)
1166 make_user_block(user1, user4)
1167 make_user_block(user5, user1)
1169 # make non-existent user admin
1170 with pytest.raises(grpc.RpcError) as e:
1171 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=999))
1172 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1173 assert e.value.details() == "Couldn't find that user."
1175 # make invisible user admin
1176 with pytest.raises(grpc.RpcError) as e:
1177 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id))
1178 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1179 assert e.value.details() == "Couldn't find that user."
1181 # make blocked user admin
1182 with pytest.raises(grpc.RpcError) as e:
1183 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user4.id))
1184 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1185 assert e.value.details() == "Couldn't find that user."
1187 # make blocking user admin
1188 with pytest.raises(grpc.RpcError) as e:
1189 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user5.id))
1190 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1191 assert e.value.details() == "Couldn't find that user."
1193 with session_scope() as session:
1194 subscriptions = (
1195 session.execute(
1196 select(GroupChatSubscription)
1197 .where(GroupChatSubscription.group_chat_id == gcid)
1198 .where(GroupChatSubscription.role == GroupChatRole.participant)
1199 )
1200 .scalars()
1201 .all()
1202 )
1204 for subscription in subscriptions:
1205 subscription.role = GroupChatRole.admin
1207 with conversations_session(token1) as c:
1208 # remove non-existent user admin
1209 with pytest.raises(grpc.RpcError) as e:
1210 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=999))
1211 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1212 assert e.value.details() == "Couldn't find that user."
1214 # remove invisible admin
1215 with pytest.raises(grpc.RpcError) as e:
1216 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id))
1217 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1218 assert e.value.details() == "Couldn't find that user."
1220 # remove blocked admin
1221 with pytest.raises(grpc.RpcError) as e:
1222 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user4.id))
1223 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1224 assert e.value.details() == "Couldn't find that user."
1226 # remove blocking admin
1227 with pytest.raises(grpc.RpcError) as e:
1228 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user5.id))
1229 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1230 assert e.value.details() == "Couldn't find that user."
1233def test_last_seen(db, moderator):
1234 user1, token1 = generate_user()
1235 user2, token2 = generate_user()
1236 user3, token3 = generate_user()
1238 make_friends(user1, user2)
1239 make_friends(user1, user3)
1240 make_friends(user2, user3)
1242 with conversations_session(token3) as c:
1243 # this is just here to mess up any issues we get if we pretend there's only one group chat ever
1244 gcid_distraction = c.CreateGroupChat(
1245 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user1.id])
1246 ).group_chat_id
1247 moderator.approve_group_chat(gcid_distraction)
1249 with conversations_session(token1) as c:
1250 gcid = c.CreateGroupChat(
1251 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])
1252 ).group_chat_id
1253 moderator.approve_group_chat(gcid)
1255 message_ids = []
1257 for i in range(6):
1258 c.SendMessage(
1259 conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text=f"gibberish message... {i}")
1260 )
1261 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text=f"test message {i}"))
1262 c.SendMessage(
1263 conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text=f"gibberish message {i}")
1264 )
1266 message_ids.append(
1267 c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)).latest_message.message_id
1268 )
1270 # messages are automatically marked as seen when you send a new message
1271 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1272 assert res.unseen_message_count == 0
1274 with conversations_session(token2) as c:
1275 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1276 # created + 6 normal
1277 assert res.unseen_message_count == 7
1279 backward_offset = 3
1280 c.MarkLastSeenGroupChat(
1281 conversations_pb2.MarkLastSeenGroupChatReq(
1282 group_chat_id=gcid, last_seen_message_id=message_ids[-backward_offset - 1]
1283 )
1284 )
1286 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1287 assert res.unseen_message_count == backward_offset
1289 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="test message ..."))
1291 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1292 assert res.unseen_message_count == 0
1294 with conversations_session(token3) as c:
1295 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1296 # created + 7 normal
1297 assert res.unseen_message_count == 8
1299 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="test message ..."))
1301 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1302 assert res.unseen_message_count == 0
1305def test_one_dm_per_pair(db, moderator):
1306 user1, token1 = generate_user()
1307 user2, token2 = generate_user()
1308 user3, token3 = generate_user()
1310 make_friends(user1, user2)
1311 make_friends(user1, user3)
1312 make_friends(user2, user3)
1314 with conversations_session(token1) as c:
1315 # create DM with user 2
1316 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
1317 assert res.is_dm
1318 dm_with_user2 = res.group_chat_id
1320 # create DM with user 3
1321 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id]))
1322 assert res.is_dm
1323 dm_with_user3 = res.group_chat_id
1325 # can't create another group chat with just user 2
1326 with pytest.raises(grpc.RpcError) as e:
1327 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
1328 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1330 # can't create another group chat with just user 3
1331 with pytest.raises(grpc.RpcError) as e:
1332 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id]))
1333 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1335 # can create joined group chat
1336 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
1337 assert not res.is_dm
1339 # Approve the DMs so user2 can see them (otherwise they're SHADOWED and only visible to creator)
1340 moderator.approve_group_chat(dm_with_user2)
1342 with conversations_session(token2) as c:
1343 # can create DM with user 3
1344 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id]))
1345 assert res.is_dm
1347 # can't create another group chat with just user 1 (DM was approved, so user2 can see it)
1348 with pytest.raises(grpc.RpcError) as e:
1349 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user1.id]))
1350 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1353def test_GetDirectMessage(db):
1354 user1, token1 = generate_user()
1355 user2, token2 = generate_user()
1356 user3, token3 = generate_user()
1358 make_friends(user1, user2)
1359 make_friends(user1, user3)
1360 make_friends(user2, user3)
1362 with conversations_session(token1) as c:
1363 # no group chat with user 2
1364 with pytest.raises(grpc.RpcError) as e:
1365 res = c.GetDirectMessage(conversations_pb2.GetDirectMessageReq(user_id=user2.id))
1366 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1368 # no group chat with nor user 3
1369 with pytest.raises(grpc.RpcError) as e:
1370 res = c.GetDirectMessage(conversations_pb2.GetDirectMessageReq(user_id=user3.id))
1371 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1373 # create DM with user 2
1374 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
1375 assert res.is_dm
1376 gcid = res.group_chat_id
1378 # now should exist
1379 res = c.GetDirectMessage(conversations_pb2.GetDirectMessageReq(user_id=user2.id))
1380 assert res.group_chat_id == gcid
1381 assert not res.is_archived
1383 # create DM with user 3
1384 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id]))
1385 assert res.is_dm
1387 # can create joined group chat
1388 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
1389 assert not res.is_dm
1391 with conversations_session(token2) as c:
1392 # can create DM with user 3
1393 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id]))
1394 assert res.is_dm
1395 assert res.can_message
1396 gcid = res.group_chat_id
1398 # DM with 3 should exist, but can't message after being blocked
1399 make_user_block(user3, user2)
1400 res = c.GetDirectMessage(conversations_pb2.GetDirectMessageReq(user_id=user3.id))
1401 assert res.group_chat_id == gcid
1402 assert not res.can_message
1405def test_total_unseen(db, moderator):
1406 user1, token1 = generate_user()
1407 user2, token2 = generate_user()
1408 user3, token3 = generate_user()
1410 # distractions
1411 user4, token4 = generate_user()
1413 make_friends(user1, user2)
1414 make_friends(user1, user3)
1415 make_friends(user2, user3)
1417 # distractions
1418 make_friends(user1, user4)
1420 with conversations_session(token1) as c:
1421 # distractions
1422 gcid_distraction = c.CreateGroupChat(
1423 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user4.id])
1424 ).group_chat_id
1425 moderator.approve_group_chat(gcid_distraction)
1426 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction..."))
1428 gcid = c.CreateGroupChat(
1429 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])
1430 ).group_chat_id
1431 moderator.approve_group_chat(gcid)
1433 for i in range(6):
1434 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text=f"test message {i}"))
1436 # distractions
1437 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction..."))
1439 # messages are automatically marked as seen when you send a new message
1440 with api_session(token1) as api:
1441 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 0
1443 with api_session(token2) as api:
1444 # chat created + 6 normal messages
1445 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 7
1447 # now leave chat with user2
1448 with conversations_session(token2) as c:
1449 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid))
1451 with api_session(token2) as api:
1452 # seen messages becomes 0 when leaving
1453 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 0
1455 with conversations_session(token1) as c:
1456 # distractions
1457 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction..."))
1459 # send more stuff without user 2
1460 for i in range(3):
1461 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text=f"test message {i}"))
1463 # distractions
1464 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction..."))
1466 with api_session(token2) as api:
1467 # seen messages becomes 0 when leaving
1468 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 0
1470 with conversations_session(token1) as c:
1471 # add user 2 back
1472 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=gcid, user_id=user2.id))
1474 # send more stuff with user 2
1475 for i in range(12):
1476 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text=f"test message {i}"))
1478 # distractions
1479 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction..."))
1481 with api_session(token2) as api:
1482 # joined + 12 normal
1483 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 13
1486def test_regression_ListGroupChats_pagination(db, moderator):
1487 user1, token1 = generate_user()
1488 user2, token2 = generate_user()
1489 user3, token3 = generate_user()
1491 make_friends(user1, user2)
1492 make_friends(user1, user3)
1494 with conversations_session(token1) as c:
1495 # tuples of (group_chat_id, message_id)
1496 group_chat_and_message_ids = []
1497 for i in range(50):
1498 res1 = c.CreateGroupChat(
1499 conversations_pb2.CreateGroupChatReq(
1500 recipient_user_ids=[user2.id, user3.id], title=wrappers_pb2.StringValue(value=f"Chat {i}")
1501 )
1502 )
1504 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res1.group_chat_id, text=f"Test message {i}"))
1506 res2 = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=res1.group_chat_id))
1508 group_chat_and_message_ids.append((res2.group_chat_id, res2.latest_message.message_id))
1509 moderator.approve_group_chat(res1.group_chat_id)
1511 seen_group_chat_ids = []
1513 last_message_id = 0
1514 more = True
1515 while more:
1516 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(last_message_id=last_message_id))
1517 last_message_id = res.last_message_id
1518 more = not res.no_more
1520 seen_group_chat_ids.extend([chat.group_chat_id for chat in res.group_chats])
1522 assert set(seen_group_chat_ids) == {x[0] for x in group_chat_and_message_ids}, "Not all group chats returned"
1525def test_muting(db, moderator):
1526 user1, token1 = generate_user()
1527 user2, token2 = generate_user()
1528 user3, token3 = generate_user()
1530 make_friends(user1, user2)
1531 make_friends(user1, user3)
1532 make_friends(user2, user3)
1534 with conversations_session(token3) as c:
1535 # this is just here to mess up any issues we get if we pretend there's only one group chat ever
1536 gcid_distraction = c.CreateGroupChat(
1537 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user1.id])
1538 ).group_chat_id
1539 moderator.approve_group_chat(gcid_distraction)
1541 with conversations_session(token1) as c:
1542 gcid = c.CreateGroupChat(
1543 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])
1544 ).group_chat_id
1545 moderator.approve_group_chat(gcid)
1547 with conversations_session(token2) as c:
1548 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1549 assert not res.mute_info.muted
1550 assert not res.mute_info.HasField("muted_until")
1552 c.MuteGroupChat(conversations_pb2.MuteGroupChatReq(group_chat_id=gcid, forever=True))
1553 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1554 assert res.mute_info.muted
1555 assert not res.mute_info.HasField("muted_until")
1557 c.MuteGroupChat(conversations_pb2.MuteGroupChatReq(group_chat_id=gcid, unmute=True))
1558 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1559 assert not res.mute_info.muted
1560 assert not res.mute_info.HasField("muted_until")
1562 c.MuteGroupChat(
1563 conversations_pb2.MuteGroupChatReq(
1564 group_chat_id=gcid, for_duration=Duration_from_timedelta(timedelta(hours=2))
1565 )
1566 )
1567 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1568 assert res.mute_info.muted
1569 assert res.mute_info.HasField("muted_until")
1570 assert to_aware_datetime(res.mute_info.muted_until) >= now() + timedelta(hours=1, minutes=59)
1571 assert to_aware_datetime(res.mute_info.muted_until) <= now() + timedelta(hours=2, minutes=1)
1574def test_archiving(db, moderator):
1575 """Test SetGroupChatArchiveStatus RPC with GetGroupChat and ListGroupChats"""
1576 user1, token1 = generate_user()
1577 user2, token2 = generate_user()
1578 user3, token3 = generate_user()
1580 make_friends(user1, user2)
1581 make_friends(user1, user3)
1582 make_friends(user2, user3)
1584 # Create a distraction chat to ensure we're testing the right one
1585 with conversations_session(token3) as c:
1586 gcid_distraction = c.CreateGroupChat(
1587 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user1.id])
1588 ).group_chat_id
1589 moderator.approve_group_chat(gcid_distraction)
1591 with conversations_session(token1) as c:
1592 gcid = c.CreateGroupChat(
1593 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])
1594 ).group_chat_id
1595 moderator.approve_group_chat(gcid)
1597 # Test basic archive/unarchive functionality
1598 with conversations_session(token2) as c:
1599 # Initially not archived
1600 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1601 assert not res.is_archived
1603 # Archive the chat
1604 archive_res = c.SetGroupChatArchiveStatus(
1605 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
1606 )
1607 assert archive_res.group_chat_id == gcid
1608 assert archive_res.is_archived
1610 # Verify archived via GetGroupChat
1611 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1612 assert res.is_archived
1614 # Unarchive the chat
1615 archive_res = c.SetGroupChatArchiveStatus(
1616 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False)
1617 )
1618 assert archive_res.group_chat_id == gcid
1619 assert not archive_res.is_archived
1621 # Verify unarchived via GetGroupChat
1622 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1623 assert not res.is_archived
1626def test_archiving_per_user(db, moderator):
1627 """Test that archiving is per-user - one user archiving doesn't affect others"""
1628 user1, token1 = generate_user()
1629 user2, token2 = generate_user()
1631 make_friends(user1, user2)
1633 with conversations_session(token1) as c:
1634 gcid = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id
1635 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello"))
1636 moderator.approve_group_chat(gcid)
1638 # User1 archives the chat
1639 with conversations_session(token1) as c:
1640 c.SetGroupChatArchiveStatus(
1641 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
1642 )
1643 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1644 assert res.is_archived
1646 # User2 should NOT see it as archived
1647 with conversations_session(token2) as c:
1648 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1649 assert not res.is_archived
1651 # User2 archives it too
1652 with conversations_session(token2) as c:
1653 c.SetGroupChatArchiveStatus(
1654 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
1655 )
1656 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1657 assert res.is_archived
1659 # User1 unarchives - user2 should still see it as archived
1660 with conversations_session(token1) as c:
1661 c.SetGroupChatArchiveStatus(
1662 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False)
1663 )
1664 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1665 assert not res.is_archived
1667 with conversations_session(token2) as c:
1668 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1669 assert res.is_archived
1672def test_archiving_with_list_group_chats(db, moderator):
1673 """Test archive filtering with ListGroupChats endpoint"""
1674 user1, token1 = generate_user()
1675 user2, token2 = generate_user()
1676 user3, token3 = generate_user()
1678 make_friends(user1, user2)
1679 make_friends(user1, user3)
1681 with conversations_session(token1) as c:
1682 # Create 3 chats
1683 gcid1 = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id
1684 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid1, text="Chat 1"))
1685 moderator.approve_group_chat(gcid1)
1687 gcid2 = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id])).group_chat_id
1688 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid2, text="Chat 2"))
1689 moderator.approve_group_chat(gcid2)
1691 gcid3 = c.CreateGroupChat(
1692 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])
1693 ).group_chat_id
1694 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid3, text="Chat 3"))
1695 moderator.approve_group_chat(gcid3)
1697 with conversations_session(token1) as c:
1698 # Initially all 3 chats should be visible
1699 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
1700 assert len(res.group_chats) == 3
1702 # All should be non-archived
1703 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False))
1704 assert len(res.group_chats) == 3
1706 # None should be archived
1707 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True))
1708 assert len(res.group_chats) == 0
1710 # Archive chat 1
1711 c.SetGroupChatArchiveStatus(
1712 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid1, is_archived=True)
1713 )
1715 # Without filter, still see all 3
1716 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
1717 assert len(res.group_chats) == 3
1719 # Non-archived should show 2
1720 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False))
1721 assert len(res.group_chats) == 2
1722 assert gcid1 not in [gc.group_chat_id for gc in res.group_chats]
1724 # Archived should show 1
1725 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True))
1726 assert len(res.group_chats) == 1
1727 assert res.group_chats[0].group_chat_id == gcid1
1728 assert res.group_chats[0].is_archived
1730 # Archive chat 2 as well
1731 c.SetGroupChatArchiveStatus(
1732 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid2, is_archived=True)
1733 )
1735 # Non-archived should show 1
1736 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False))
1737 assert len(res.group_chats) == 1
1738 assert res.group_chats[0].group_chat_id == gcid3
1740 # Archived should show 2
1741 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True))
1742 assert len(res.group_chats) == 2
1743 archived_ids = {gc.group_chat_id for gc in res.group_chats}
1744 assert archived_ids == {gcid1, gcid2}
1746 # Unarchive chat 1
1747 c.SetGroupChatArchiveStatus(
1748 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid1, is_archived=False)
1749 )
1751 # Non-archived should show 2
1752 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False))
1753 assert len(res.group_chats) == 2
1755 # Archived should show 1
1756 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True))
1757 assert len(res.group_chats) == 1
1758 assert res.group_chats[0].group_chat_id == gcid2
1761def test_archiving_chat_not_found(db, moderator):
1762 """Test that archiving a non-existent or non-accessible chat fails"""
1763 user1, token1 = generate_user()
1764 user2, token2 = generate_user()
1765 user3, token3 = generate_user()
1767 make_friends(user1, user2)
1769 with conversations_session(token1) as c:
1770 gcid = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id
1771 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello"))
1772 moderator.approve_group_chat(gcid)
1774 # User3 is not in the chat - should get NOT_FOUND
1775 with conversations_session(token3) as c:
1776 with pytest.raises(grpc.RpcError) as e:
1777 c.SetGroupChatArchiveStatus(
1778 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
1779 )
1780 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1782 # Non-existent chat ID should fail
1783 with conversations_session(token1) as c:
1784 with pytest.raises(grpc.RpcError) as e:
1785 c.SetGroupChatArchiveStatus(
1786 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=99999, is_archived=True)
1787 )
1788 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1791def test_archiving_after_leaving_chat(db, moderator):
1792 """Test that you can't archive a chat after leaving it"""
1793 user1, token1 = generate_user()
1794 user2, token2 = generate_user()
1795 user3, token3 = generate_user()
1797 make_friends(user1, user2)
1798 make_friends(user1, user3)
1799 make_friends(user2, user3)
1801 with conversations_session(token1) as c:
1802 gcid = c.CreateGroupChat(
1803 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])
1804 ).group_chat_id
1805 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello"))
1806 moderator.approve_group_chat(gcid)
1808 # User2 leaves the chat
1809 with conversations_session(token2) as c:
1810 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid))
1812 # User2 should not be able to archive it now
1813 with conversations_session(token2) as c:
1814 with pytest.raises(grpc.RpcError) as e:
1815 c.SetGroupChatArchiveStatus(
1816 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
1817 )
1818 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1821def test_archiving_dm(db, moderator):
1822 """Test that archiving works for DMs as well as group chats"""
1823 user1, token1 = generate_user()
1824 user2, token2 = generate_user()
1826 make_friends(user1, user2)
1828 with conversations_session(token1) as c:
1829 # Create a DM
1830 gcid = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id
1831 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello"))
1832 moderator.approve_group_chat(gcid)
1834 # Verify it's a DM
1835 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1836 assert res.is_dm
1837 assert not res.is_archived
1839 # Archive the DM
1840 c.SetGroupChatArchiveStatus(
1841 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
1842 )
1844 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1845 assert res.is_archived
1847 # Unarchive it
1848 c.SetGroupChatArchiveStatus(
1849 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False)
1850 )
1852 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1853 assert not res.is_archived
1856def test_archiving_idempotent(db, moderator):
1857 """Test that archiving/unarchiving is idempotent"""
1858 user1, token1 = generate_user()
1859 user2, token2 = generate_user()
1861 make_friends(user1, user2)
1863 with conversations_session(token1) as c:
1864 gcid = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id
1865 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello"))
1866 moderator.approve_group_chat(gcid)
1868 # Archive twice - should work without error
1869 c.SetGroupChatArchiveStatus(
1870 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
1871 )
1872 c.SetGroupChatArchiveStatus(
1873 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
1874 )
1875 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1876 assert res.is_archived
1878 # Unarchive twice - should work without error
1879 c.SetGroupChatArchiveStatus(
1880 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False)
1881 )
1882 c.SetGroupChatArchiveStatus(
1883 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False)
1884 )
1885 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1886 assert not res.is_archived
1889def test_chat_notifications(db, moderator):
1890 user1, token1 = generate_user()
1891 user2, token2 = generate_user()
1892 # notifs off
1893 user3, token3 = generate_user()
1894 user4, token4 = generate_user()
1895 user5, token5 = generate_user()
1896 user6, token6 = generate_user()
1898 make_friends(user1, user2)
1899 make_friends(user1, user3)
1900 make_friends(user1, user4)
1901 make_friends(user4, user5)
1902 make_friends(user4, user6)
1904 # have some of them enable/disable notifs
1905 topic_action = NotificationTopicAction.chat__message
1906 for token, enabled in [
1907 (token1, True),
1908 (token2, True),
1909 (token3, False),
1910 (token4, True),
1911 (token5, True),
1912 (token6, True),
1913 ]:
1914 with notifications_session(token) as notifications:
1915 notifications.SetNotificationSettings(
1916 notifications_pb2.SetNotificationSettingsReq(
1917 preferences=[
1918 notifications_pb2.SingleNotificationPreference(
1919 topic=topic_action.topic,
1920 action=topic_action.action,
1921 delivery_method=delivery_method,
1922 enabled=enabled,
1923 )
1924 for delivery_method in ["push", "email", "digest"]
1925 ],
1926 )
1927 )
1929 group_chat_id = None
1931 def send_msg(c, i):
1932 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text=f"Test message {i}"))
1934 with conversations_session(token1) as c:
1935 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id, user4.id]))
1936 group_chat_id = res.group_chat_id
1937 moderator.approve_group_chat(group_chat_id)
1938 c.EditGroupChat(
1939 conversations_pb2.EditGroupChatReq(
1940 group_chat_id=group_chat_id, only_admins_invite=wrappers_pb2.BoolValue(value=False)
1941 )
1942 )
1943 send_msg(c, i=1)
1944 send_msg(c, i=2)
1946 with conversations_session(token4) as c:
1947 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user5.id))
1948 send_msg(c, i=3)
1949 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user6.id))
1950 send_msg(c, i=4)
1951 send_msg(c, i=5)
1953 with conversations_session(token3) as c:
1954 send_msg(c, i=6)
1955 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
1957 with conversations_session(token2) as c:
1958 send_msg(c, i=7)
1959 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
1961 with conversations_session(token6) as c:
1962 send_msg(c, i=8)
1964 # go through all bg jobs
1965 while process_job():
1966 pass
1968 # now check notifs...
1969 expected_notifs = [
1970 (user1, "user1", [3, 4, 5, 6, 7, 8]),
1971 (user2, "user2", [1, 2, 3, 4, 5, 6]),
1972 (user3, "user3", []), # notifs off
1973 (user4, "user4", [1, 2, 6, 7, 8]),
1974 (user5, "user5", [3, 4, 5, 6, 7, 8]),
1975 (user6, "user6", [4, 5, 6, 7]),
1976 ]
1978 with session_scope() as session:
1979 for user, label, expected_msgs in expected_notifs:
1980 deliv = (
1981 session.execute(
1982 select(Notification.data)
1983 .join(NotificationDelivery, NotificationDelivery.notification_id == Notification.id)
1984 .where(Notification.user_id == user.id)
1985 .where(Notification.topic_action == topic_action)
1986 .where(NotificationDelivery.delivery_type == NotificationDeliveryType.push)
1987 .order_by(Notification.created)
1988 )
1989 .scalars()
1990 .all()
1991 )
1993 def parse_message_payload(data):
1994 return notification_data_pb2.ChatMessage.FromString(data).text
1996 contents = [parse_message_payload(d) for d in deliv]
1998 print(contents)
2000 assert [f"Test message {i}" for i in expected_msgs] == contents, f"Wrong messages for {label}"
2003def test_incomplete_profile(db):
2004 user1, token1 = generate_user(complete_profile=True)
2005 user2, token2 = generate_user(complete_profile=False)
2006 user3, token3 = generate_user(complete_profile=True)
2007 make_friends(user1, user2)
2008 make_friends(user1, user3)
2010 # user 1 can make a chat
2011 with conversations_session(token1) as c:
2012 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
2013 group_chat_id = res.group_chat_id
2014 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
2015 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
2016 assert res.messages[0].text.text == "Test message 1"
2017 assert to_aware_datetime(res.messages[0].time) <= now()
2018 assert res.messages[0].author_user_id == user1.id
2020 # user 2 cannot
2021 with conversations_session(token2) as c:
2022 with pytest.raises(grpc.RpcError) as e:
2023 c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id]))
2024 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
2025 assert e.value.details() == "You have to complete your profile before you can send a message."