Coverage for app/backend/src/tests/test_conversations.py: 100%
1322 statements
« prev ^ index » next coverage.py v7.15.3, created at 2026-08-04 22:32 +0000
« prev ^ index » next coverage.py v7.15.3, created at 2026-08-04 22:32 +0000
1from datetime import timedelta
2from unittest.mock import patch
4import grpc
5import pytest
6from google.protobuf import empty_pb2, wrappers_pb2
7from sqlalchemy import func, select
9from couchers.db import session_scope
10from couchers.jobs.handlers import send_message_notifications
11from couchers.jobs.worker import process_job
12from couchers.models import (
13 GroupChatRole,
14 GroupChatSubscription,
15 Notification,
16 NotificationDelivery,
17 NotificationDeliveryType,
18 NotificationTopicAction,
19 RateLimitAction,
20)
21from couchers.proto import api_pb2, conversations_pb2, notification_data_pb2, notifications_pb2
22from couchers.rate_limits.definitions import RATE_LIMIT_DEFINITIONS, RATE_LIMIT_HOURS
23from couchers.utils import Duration_from_timedelta, now, to_aware_datetime
24from tests.fixtures.db import generate_user, make_friends, make_user_block, make_user_invisible
25from tests.fixtures.misc import EmailCollector, Moderator, PushCollector, now_5_min_in_future, process_jobs
26from tests.fixtures.sessions import api_session, conversations_session, notifications_session
29@pytest.fixture(autouse=True)
30def _(testconfig):
31 pass
34def test_list_group_chats(db, moderator):
35 user1, token1 = generate_user()
36 user2, token2 = generate_user()
37 user3, token3 = generate_user()
39 make_friends(user2, user1)
40 make_friends(user1, user3)
42 with conversations_session(token1) as c:
43 # no threads initially
44 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
45 assert len(res.group_chats) == 0
47 # create some group chats with messages
48 res = c.CreateGroupChat(
49 conversations_pb2.CreateGroupChatReq(
50 recipient_user_ids=[user2.id], title=wrappers_pb2.StringValue(value="Test title")
51 )
52 )
53 group_chat1_id = res.group_chat_id
54 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message 1"))
55 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message 2"))
56 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
57 group_chat2_id = res.group_chat_id
58 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test group message 1"))
59 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test group message 2"))
61 moderator.approve_group_chat(group_chat1_id)
62 moderator.approve_group_chat(group_chat2_id)
64 with conversations_session(token1) as c:
65 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
66 assert len(res.group_chats) == 2
67 assert res.no_more
69 with conversations_session(token2) as c:
70 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
71 assert len(res.group_chats) == 2
72 assert res.no_more
74 with conversations_session(token3) as c:
75 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
76 assert len(res.group_chats) == 1
77 assert res.no_more
79 # Test archive filtering: archive group_chat1 for user1
80 with conversations_session(token1) as c:
81 res = c.SetGroupChatArchiveStatus(
82 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=group_chat1_id, is_archived=True)
83 )
84 assert res.group_chat_id == group_chat1_id
85 assert res.is_archived
87 with conversations_session(token1) as c:
88 # Without filter, returns all chats
89 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
90 assert len(res.group_chats) == 2
92 # only_archived=False returns non-archived chats only
93 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False))
94 assert len(res.group_chats) == 1
96 # only_archived=True returns archived chats only
97 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True))
98 assert len(res.group_chats) == 1
100 # user2 should still see both as non-archived (archive is per-user)
101 with conversations_session(token2) as c:
102 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False))
103 assert len(res.group_chats) == 2
105 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True))
106 assert len(res.group_chats) == 0
109def test_list_empty_group_chats(db, moderator):
110 user1, token1 = generate_user()
111 user2, token2 = generate_user()
112 user3, token3 = generate_user()
114 make_friends(user1, user3)
115 make_friends(user2, user1)
116 make_friends(user2, user3)
118 with conversations_session(token1) as c:
119 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
120 assert len(res.group_chats) == 0
122 res1 = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
123 res2 = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
125 moderator.approve_group_chat(res1.group_chat_id)
126 moderator.approve_group_chat(res2.group_chat_id)
128 with conversations_session(token1) as c:
129 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
130 assert len(res.group_chats) == 2
131 assert res.no_more
133 with conversations_session(token2) as c:
134 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
135 assert len(res.group_chats) == 2
136 assert res.no_more
138 res3 = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id]))
139 moderator.approve_group_chat(res3.group_chat_id)
141 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
142 assert len(res.group_chats) == 3
143 assert res.no_more
145 with conversations_session(token3) as c:
146 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
147 assert len(res.group_chats) == 2
148 assert res.no_more
151def test_list_group_chats_ordering(db, moderator):
152 # user is member of 5 group chats, order them correctly
153 user, token = generate_user()
154 user2, token2 = generate_user()
155 user3, token3 = generate_user()
156 user4, token4 = generate_user()
158 make_friends(user2, user)
159 make_friends(user2, user3)
160 make_friends(user2, user4)
161 make_friends(user3, user)
162 make_friends(user3, user4)
163 make_friends(user, user4)
165 chat_ids = []
167 with conversations_session(token2) as c:
168 res = c.CreateGroupChat(
169 conversations_pb2.CreateGroupChatReq(
170 recipient_user_ids=[user.id], title=wrappers_pb2.StringValue(value="Chat 0")
171 )
172 )
173 chat_ids.append(res.group_chat_id)
174 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
175 res = c.CreateGroupChat(
176 conversations_pb2.CreateGroupChatReq(
177 recipient_user_ids=[user.id, user3.id], title=wrappers_pb2.StringValue(value="Chat 1")
178 )
179 )
180 chat_ids.append(res.group_chat_id)
181 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
182 res = c.CreateGroupChat(
183 conversations_pb2.CreateGroupChatReq(
184 recipient_user_ids=[user.id, user3.id], title=wrappers_pb2.StringValue(value="Chat 2")
185 )
186 )
187 chat_ids.append(res.group_chat_id)
188 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
190 with conversations_session(token3) as c:
191 res = c.CreateGroupChat(
192 conversations_pb2.CreateGroupChatReq(
193 recipient_user_ids=[user.id, user2.id, user4.id], title=wrappers_pb2.StringValue(value="Chat 3")
194 )
195 )
196 chat_ids.append(res.group_chat_id)
197 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
199 for chat_id in chat_ids:
200 moderator.approve_group_chat(chat_id)
202 with conversations_session(token) as c:
203 res = c.CreateGroupChat(
204 conversations_pb2.CreateGroupChatReq(
205 recipient_user_ids=[user2.id, user3.id, user4.id], title=wrappers_pb2.StringValue(value="Chat 4")
206 )
207 )
208 moderator.approve_group_chat(res.group_chat_id)
209 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
210 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
211 assert len(res.group_chats) == 5
212 assert res.group_chats[0].title == "Chat 4"
213 assert res.group_chats[1].title == "Chat 3"
214 assert res.group_chats[2].title == "Chat 2"
215 assert res.group_chats[3].title == "Chat 1"
216 assert res.group_chats[4].title == "Chat 0"
218 c.SendMessage(
219 conversations_pb2.SendMessageReq(group_chat_id=res.group_chats[3].group_chat_id, text="Test message 2a")
220 )
221 c.SendMessage(
222 conversations_pb2.SendMessageReq(group_chat_id=res.group_chats[2].group_chat_id, text="Test message 2b")
223 )
225 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
226 assert len(res.group_chats) == 5
227 assert res.group_chats[0].title == "Chat 2"
228 assert res.group_chats[0].latest_message.text.text == "Test message 2b"
229 assert res.group_chats[1].title == "Chat 1"
230 assert res.group_chats[1].latest_message.text.text == "Test message 2a"
231 assert res.group_chats[2].title == "Chat 4"
232 assert res.group_chats[3].title == "Chat 3"
233 assert res.group_chats[4].title == "Chat 0"
236def test_list_group_chats_ordering_after_left(db, moderator):
237 # user is member to 4 group chats, and has left one.
238 # The one user left has the most recent message, but user left before then,
239 # this should display as e.g. 3rd most recent depending on last message when they were in the chat
240 user, token = generate_user()
241 user2, token2 = generate_user()
242 user3, token3 = generate_user()
243 user4, token4 = generate_user()
245 make_friends(user2, user)
246 make_friends(user2, user3)
247 make_friends(user2, user4)
248 make_friends(user3, user)
249 make_friends(user3, user4)
250 make_friends(user, user4)
252 chat_ids = []
254 with conversations_session(token2) as c:
255 res = c.CreateGroupChat(
256 conversations_pb2.CreateGroupChatReq(
257 recipient_user_ids=[user.id], title=wrappers_pb2.StringValue(value="Chat 0")
258 )
259 )
260 chat_ids.append(res.group_chat_id)
261 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
262 res = c.CreateGroupChat(
263 conversations_pb2.CreateGroupChatReq(
264 recipient_user_ids=[user.id, user3.id], title=wrappers_pb2.StringValue(value="Left Chat 1")
265 )
266 )
267 left_chat_id = res.group_chat_id
268 chat_ids.append(left_chat_id)
269 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=left_chat_id, text="Test message"))
270 res = c.CreateGroupChat(
271 conversations_pb2.CreateGroupChatReq(
272 recipient_user_ids=[user.id, user3.id], title=wrappers_pb2.StringValue(value="Chat 2")
273 )
274 )
275 chat2_id = res.group_chat_id
276 chat_ids.append(chat2_id)
277 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=chat2_id, text="Test message"))
279 with conversations_session(token3) as c:
280 res = c.CreateGroupChat(
281 conversations_pb2.CreateGroupChatReq(
282 recipient_user_ids=[user.id, user2.id, user4.id], title=wrappers_pb2.StringValue(value="Chat 3")
283 )
284 )
285 chat_ids.append(res.group_chat_id)
286 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
288 for chat_id in chat_ids:
289 moderator.approve_group_chat(chat_id)
291 with conversations_session(token) as c:
292 res = c.CreateGroupChat(
293 conversations_pb2.CreateGroupChatReq(
294 recipient_user_ids=[user2.id, user3.id, user4.id], title=wrappers_pb2.StringValue(value="Chat 4")
295 )
296 )
297 moderator.approve_group_chat(res.group_chat_id)
298 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message"))
300 # leave chat
301 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=left_chat_id))
303 with conversations_session(token3) as c:
304 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=chat2_id, text="Test message"))
305 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=left_chat_id, text="Test message"))
307 with conversations_session(token2) as c:
308 # other user sends a message to that chat
309 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=left_chat_id, text="Another test message"))
310 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
311 assert len(res.group_chats) == 5
312 assert res.group_chats[0].title == "Left Chat 1"
313 assert res.group_chats[1].title == "Chat 2"
314 assert res.group_chats[2].title == "Chat 4"
315 assert res.group_chats[3].title == "Chat 3"
316 assert res.group_chats[4].title == "Chat 0"
318 with conversations_session(token) as c:
319 # we can't see the new message since we left before it was sent
320 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
321 assert len(res.group_chats) == 5
322 assert res.group_chats[0].title == "Chat 2"
323 assert res.group_chats[1].title == "Left Chat 1"
324 assert res.group_chats[2].title == "Chat 4"
325 assert res.group_chats[3].title == "Chat 3"
326 assert res.group_chats[4].title == "Chat 0"
329def test_get_group_chat_messages(db):
330 user1, token1 = generate_user()
331 user2, token2 = generate_user()
332 user3, token3 = generate_user()
334 make_friends(user1, user2)
336 with conversations_session(token1) as c:
337 # create some threads with messages
338 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
339 group_chat_id = res.group_chat_id
340 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message 1"))
341 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message 2"))
343 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
344 # created + 2 normal
345 assert len(res.messages) == 3
346 assert res.no_more
348 assert res.messages[0].text.text == "Test message 2"
349 assert res.messages[1].text.text == "Test message 1"
350 assert res.messages[2].WhichOneof("content") == "chat_created"
352 # test that another user can't access the thread
353 with conversations_session(token3) as c:
354 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
355 assert len(res.messages) == 0
358def test_get_group_chat_messages_pagination(db, moderator):
359 user1, token1 = generate_user()
360 user2, token2 = generate_user()
361 make_friends(user1, user2)
363 with conversations_session(token1) as c:
364 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
365 group_chat_id = res.group_chat_id
366 for i in range(30):
367 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text=str(i)))
369 moderator.approve_group_chat(group_chat_id)
371 with conversations_session(token2) as c:
372 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
373 # pagination
374 assert len(res.messages) == 20
375 assert res.messages[0].text.text == "29"
376 assert res.messages[19].text.text == "10"
377 assert not res.no_more
378 res = c.GetGroupChatMessages(
379 conversations_pb2.GetGroupChatMessagesReq(
380 group_chat_id=group_chat_id, last_message_id=res.messages[19].message_id
381 )
382 )
383 assert len(res.messages) == 11
384 assert res.messages[0].text.text == "9"
385 assert res.messages[9].text.text == "0"
386 assert res.no_more
389def test_get_group_chat_messages_joined_left(db, moderator):
390 user1, token1 = generate_user()
391 user2, token2 = generate_user()
392 user3, token3 = generate_user()
393 user4, token4 = generate_user()
394 make_friends(user1, user2)
395 make_friends(user1, user3)
396 make_friends(user1, user4)
398 with conversations_session(token1) as c:
399 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user4.id]))
400 group_chat_id = res.group_chat_id
401 moderator.approve_group_chat(group_chat_id)
403 for i in range(10):
404 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text=str(i)))
406 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id))
408 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="10"))
410 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
412 # created + 10 normal + invited + normal
413 assert len(res.messages) == 13
415 with conversations_session(token3) as c:
416 # can only see last message after invited
417 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
418 # joined + normal
419 assert len(res.messages) == 2
420 assert res.messages[0].text.text == "10"
422 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
424 with conversations_session(token1) as c:
425 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="11"))
426 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="12"))
428 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id))
430 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="13"))
431 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="14"))
433 with conversations_session(token3) as c:
434 # can only see last message after invited
435 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
436 # joined + normal + left + invite + 2 normal
437 assert len(res.messages) == 6
438 assert res.messages[0].text.text == "14"
439 assert res.messages[1].text.text == "13"
440 assert res.messages[2].WhichOneof("content") == "user_invited"
441 assert res.messages[3].WhichOneof("content") == "user_left"
442 assert res.messages[4].text.text == "10"
443 assert res.messages[5].WhichOneof("content") == "user_invited"
446def test_get_group_chat_info(db):
447 user1, token1 = generate_user()
448 user2, token2 = generate_user()
449 user3, token3 = generate_user()
451 make_friends(user1, user2)
452 make_friends(user3, user1)
454 with conversations_session(token1) as c:
455 # create some threads with messages
456 res = c.CreateGroupChat(
457 conversations_pb2.CreateGroupChatReq(
458 recipient_user_ids=[user2.id], title=wrappers_pb2.StringValue(value="Test title")
459 )
460 )
461 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message 1"))
462 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test message 2"))
463 group_chat1_id = res.group_chat_id
464 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
465 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test group message 1"))
466 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res.group_chat_id, text="Test group message 2"))
467 group_chat2_id = res.group_chat_id
469 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat1_id))
470 assert res.title == "Test title"
471 assert user2.id in res.member_user_ids
472 assert user1.id in res.admin_user_ids
473 assert to_aware_datetime(res.created) <= now()
474 assert res.only_admins_invite
475 assert res.is_dm
476 assert not res.is_archived
478 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat2_id))
479 assert not res.title
480 assert user2.id in res.member_user_ids
481 assert user3.id in res.member_user_ids
482 assert user1.id in res.admin_user_ids
483 assert to_aware_datetime(res.created) <= now()
484 assert res.only_admins_invite
485 assert not res.is_dm
486 assert not res.is_archived
489def test_get_group_chat_info_denied(db):
490 user1, token1 = generate_user()
491 user2, token2 = generate_user()
492 user3, token3 = generate_user()
493 user4, token4 = generate_user()
495 make_friends(user1, user2)
496 make_friends(user3, user1)
498 with conversations_session(token1) as c:
499 # create a group chat with messages
500 res = c.CreateGroupChat(
501 conversations_pb2.CreateGroupChatReq(
502 recipient_user_ids=[user2.id, user3.id], title=wrappers_pb2.StringValue(value="Test title")
503 )
504 )
505 group_chat_id = res.group_chat_id
506 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
508 with conversations_session(token4) as c:
509 with pytest.raises(grpc.RpcError) as e:
510 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
511 assert e.value.code() == grpc.StatusCode.NOT_FOUND
514def test_get_group_chat_info_left(db, moderator):
515 user1, token1 = generate_user()
516 user2, token2 = generate_user()
517 user3, token3 = generate_user()
518 user4, token4 = generate_user()
520 make_friends(user1, user2)
521 make_friends(user3, user1)
522 make_friends(user1, user4)
524 with conversations_session(token1) as c:
525 # create a group chat with messages
526 res = c.CreateGroupChat(
527 conversations_pb2.CreateGroupChatReq(
528 recipient_user_ids=[user2.id, user3.id], title=wrappers_pb2.StringValue(value="Test title")
529 )
530 )
531 group_chat_id = res.group_chat_id
532 moderator.approve_group_chat(group_chat_id)
533 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
535 with conversations_session(token3) as c:
536 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
538 with conversations_session(token1) as c:
539 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user4.id))
541 with conversations_session(token3) as c:
542 # this user left when user4 wasn't a member,
543 # so the returned members should be user1, user2, and user3 only
544 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
545 assert len(res.member_user_ids) == 3
546 assert user1.id in res.member_user_ids
547 assert user2.id in res.member_user_ids
548 assert user3.id in res.member_user_ids
551def test_remove_group_chat_user(db):
552 # create 3 uses and connect them
553 user1, token1 = generate_user()
554 user2, token2 = generate_user()
555 user3, token3 = generate_user()
556 make_friends(user1, user2)
557 make_friends(user1, user3)
559 # using user token, create a Conversations API for testing
560 with conversations_session(token1) as c:
561 # create a group chat
562 res = c.CreateGroupChat(
563 conversations_pb2.CreateGroupChatReq(
564 recipient_user_ids=[user2.id, user3.id], title=wrappers_pb2.StringValue(value="Test title")
565 )
566 )
567 group_chat_id = res.group_chat_id
569 # remove a user from group
570 c.RemoveGroupChatUser(conversations_pb2.RemoveGroupChatUserReq(group_chat_id=group_chat_id, user_id=user2.id))
571 assert user3.id in res.member_user_ids # other users are still in the group
573 # can't remove the same user twice
574 with pytest.raises(grpc.RpcError) as e:
575 c.RemoveGroupChatUser(
576 conversations_pb2.RemoveGroupChatUserReq(group_chat_id=group_chat_id, user_id=user2.id)
577 )
578 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
581def test_edit_group_chat(db, moderator):
582 user1, token1 = generate_user()
583 user2, token2 = generate_user()
584 user3, token3 = generate_user()
585 make_friends(user1, user2)
587 with conversations_session(token1) as c:
588 # create some threads with messages
589 res = c.CreateGroupChat(
590 conversations_pb2.CreateGroupChatReq(
591 recipient_user_ids=[user2.id], title=wrappers_pb2.StringValue(value="Test title")
592 )
593 )
594 group_chat_id = res.group_chat_id
595 moderator.approve_group_chat(group_chat_id)
597 c.EditGroupChat(
598 conversations_pb2.EditGroupChatReq(
599 group_chat_id=group_chat_id,
600 title=wrappers_pb2.StringValue(value="Modified title"),
601 only_admins_invite=wrappers_pb2.BoolValue(value=False),
602 )
603 )
604 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
605 assert res.title == "Modified title"
606 assert not res.only_admins_invite
608 # make sure non-admin is not allowed to modify
609 with conversations_session(token2) as c:
610 with pytest.raises(grpc.RpcError) as e:
611 c.EditGroupChat(
612 conversations_pb2.EditGroupChatReq(
613 group_chat_id=group_chat_id,
614 title=wrappers_pb2.StringValue(value="Other title"),
615 only_admins_invite=wrappers_pb2.BoolValue(value=True),
616 )
617 )
618 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED
620 # make sure non-recipient is not allowed to modify
621 with conversations_session(token3) as c:
622 with pytest.raises(grpc.RpcError) as e:
623 c.EditGroupChat(
624 conversations_pb2.EditGroupChatReq(
625 group_chat_id=group_chat_id,
626 title=wrappers_pb2.StringValue(value="Other title"),
627 only_admins_invite=wrappers_pb2.BoolValue(value=True),
628 )
629 )
630 assert e.value.code() == grpc.StatusCode.NOT_FOUND
633def test_make_remove_group_chat_admin(db, moderator):
634 user1, token1 = generate_user()
635 user2, token2 = generate_user()
636 user3, token3 = generate_user()
638 make_friends(user1, user2)
639 make_friends(user1, user3)
640 make_friends(user2, user3)
642 with conversations_session(token1) as c:
643 # create some threads with messages
644 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
645 group_chat_id = res.group_chat_id
646 moderator.approve_group_chat(group_chat_id)
648 # shouldn't be able to remove only admin
649 with pytest.raises(grpc.RpcError) as e:
650 c.RemoveGroupChatAdmin(
651 conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=group_chat_id, user_id=user1.id)
652 )
653 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
654 assert e.value.details() == "You can't remove the last admin."
656 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=group_chat_id, user_id=user2.id))
658 # shouldn't be able to make admin again
659 with pytest.raises(grpc.RpcError) as e:
660 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=group_chat_id, user_id=user2.id))
661 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
662 assert e.value.details() == "That user is already an admin."
664 with conversations_session(token2) as c:
665 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
666 assert user1.id in res.admin_user_ids
667 assert user2.id in res.admin_user_ids
669 with conversations_session(token1) as c:
670 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=group_chat_id, user_id=user2.id))
672 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
673 assert user1.id in res.admin_user_ids
674 assert user2.id not in res.admin_user_ids
676 with conversations_session(token2) as c:
677 # shouldn't be able to make admin if not admin
678 with pytest.raises(grpc.RpcError) as e:
679 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=group_chat_id, user_id=user3.id))
680 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED
683def test_send_message(db, moderator: Moderator, push_collector: PushCollector, email_collector: EmailCollector):
684 user1, token1 = generate_user()
685 user2, token2 = generate_user()
686 user3, token3 = generate_user()
687 make_friends(user1, user2)
688 make_friends(user1, user3)
690 # Let user2 receive email notifications for every chat message
691 with notifications_session(token2) as n:
692 n.SetNotificationSettings(
693 notifications_pb2.SetNotificationSettingsReq(
694 preferences=[
695 notifications_pb2.SingleNotificationPreference(
696 topic=NotificationTopicAction.chat__message.topic,
697 action=NotificationTopicAction.chat__message.action,
698 delivery_method="email",
699 enabled=True,
700 )
701 ]
702 )
703 )
705 group_chat_title = "My group chat"
706 message1 = "Test message 1"
708 # Let user1 create a group chat with user2 and send a message
709 with conversations_session(token1) as c:
710 res = c.CreateGroupChat(
711 conversations_pb2.CreateGroupChatReq(
712 title=wrappers_pb2.StringValue(value=group_chat_title), recipient_user_ids=[user2.id]
713 )
714 )
715 group_chat_id = res.group_chat_id
716 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text=message1))
718 # Sender can already see group chat
719 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
720 assert res.messages[0].text.text == message1
721 assert to_aware_datetime(res.messages[0].time) <= now()
722 assert res.messages[0].author_user_id == user1.id
724 # user2 sees nothing until the group chat is approved
725 assert push_collector.count_for_user(user2.id) == 0
726 assert email_collector.count_for_recipient(user2.email) == 0
728 moderator.approve_group_chat(group_chat_id)
730 # user2 gets email and push notifications
731 push = push_collector.pop_for_user(user2.id, last=True)
732 assert push.topic_action == NotificationTopicAction.chat__message.display
733 assert message1 in push.content.body
735 email = email_collector.pop_for_recipient(user2.email, last=True)
736 assert group_chat_title in email.subject
737 assert message1 in email.plain
738 assert message1 in email.html
740 # can't send message if not in chat
741 with conversations_session(token3) as c:
742 with pytest.raises(grpc.RpcError) as e:
743 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 2"))
744 assert e.value.code() == grpc.StatusCode.NOT_FOUND
746 make_user_block(user2, user1)
747 with conversations_session(token1) as c:
748 with pytest.raises(grpc.RpcError) as e:
749 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Message after block"))
750 assert e.value.details() == "You can't send a message in this chat."
753def test_send_direct_message(db, moderator: Moderator, push_collector: PushCollector, email_collector: EmailCollector):
754 user1, token1 = generate_user(complete_profile=True)
755 user2, token2 = generate_user(complete_profile=True)
757 make_friends(user1, user2)
759 # Let user2 receive email notifications for every chat message
760 with notifications_session(token2) as n:
761 n.SetNotificationSettings(
762 notifications_pb2.SetNotificationSettingsReq(
763 preferences=[
764 notifications_pb2.SingleNotificationPreference(
765 topic=NotificationTopicAction.chat__message.topic,
766 action=NotificationTopicAction.chat__message.action,
767 delivery_method="email",
768 enabled=True,
769 )
770 ]
771 )
772 )
774 # Let user1 send two DM's to user2
775 message1 = "Hello, user2!"
776 message2 = "One more message."
778 with conversations_session(token1) as c1:
779 # Send a DM from user1 to user2
780 res = c1.SendDirectMessage(conversations_pb2.SendDirectMessageReq(recipient_user_id=user2.id, text=message1))
781 moderator.approve_group_chat(res.group_chat_id)
783 c1.SendDirectMessage(conversations_pb2.SendDirectMessageReq(recipient_user_id=user2.id, text=message2))
785 # user2 should have received push and email notifications for both messages
786 push = push_collector.pop_for_user(user2.id, last=False)
787 assert push.topic_action == NotificationTopicAction.chat__message.display
788 assert push.content.title == user1.name
789 assert push.content.body == message1
791 email = email_collector.pop_for_recipient(user2.email, last=False)
792 assert user1.name in email.subject
793 assert message1 in email.plain
794 assert message1 in email.html
796 push = push_collector.pop_for_user(user2.id, last=True)
797 assert push.topic_action == NotificationTopicAction.chat__message.display
798 assert push.content.title == user1.name
799 assert push.content.body == message2
801 email = email_collector.pop_for_recipient(user2.email, last=True)
802 assert user1.name in email.subject
803 assert message2 in email.plain
804 assert message2 in email.html
806 with conversations_session(token2) as c2:
807 # Fetch the chat by ID returned from SendDirectMessage
808 chat = c2.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=res.group_chat_id))
810 assert chat.is_dm
811 group_chat_id = chat.group_chat_id
813 # Verify that the messages was received
814 messages = c2.GetGroupChatMessages(
815 conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id)
816 ).messages
818 assert len(messages) == 2
819 assert messages[0].text.text == message2
820 assert messages[1].text.text == message1
821 assert messages[0].author_user_id == user1.id
824def test_excessive_chat_initiations_are_reported(db, email_collector: EmailCollector):
825 """Test that excessive chat initiations are first reported in a warning email and finally lead blocking of further contacting other users."""
826 user, token = generate_user()
827 rate_limit_definition = RATE_LIMIT_DEFINITIONS[RateLimitAction.chat_initiation]
828 with conversations_session(token) as c:
829 # Test warning email
830 for _ in range(rate_limit_definition.warning_limit):
831 recipient_user, _ = generate_user()
832 _ = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[recipient_user.id]))
834 assert email_collector.count_for_reports() == 0
836 recipient_user, _ = generate_user()
837 _ = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[recipient_user.id]))
839 email = email_collector.pop_for_reports(last=True)
840 assert email.plain.startswith(
841 f"User {user.username} has sent {rate_limit_definition.warning_limit} chat initiations in the past {RATE_LIMIT_HOURS} hours."
842 )
844 # Test new chat initiations fail after exceeding CHAT_INITIATION_HARD_LIMIT
845 for _ in range(rate_limit_definition.hard_limit - rate_limit_definition.warning_limit - 1):
846 recipient_user, _ = generate_user()
847 _ = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[recipient_user.id]))
849 assert email_collector.count_for_reports() == 0
851 recipient_user, _ = generate_user()
852 with pytest.raises(grpc.RpcError) as exc_info:
853 _ = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[recipient_user.id]))
854 assert exc_info.value.code() == grpc.StatusCode.RESOURCE_EXHAUSTED
855 assert (
856 exc_info.value.details()
857 == "You have messaged a lot of users in the past 24 hours. To avoid spam, you can't contact any more users for now."
858 )
860 email = email_collector.pop_for_reports(last=True)
861 assert email.plain.startswith(
862 f"User {user.username} has sent {rate_limit_definition.hard_limit} chat initiations in the past {RATE_LIMIT_HOURS} hours."
863 )
864 assert "The user has been blocked from sending further chat initiations for now." in email.plain
867def test_send_direct_message_rate_limit(db, moderator, email_collector: EmailCollector):
868 """SendDirectMessage should enforce the chat_initiation rate limit when creating a new DM, but not when sending into an existing one."""
869 user, token = generate_user(complete_profile=True)
870 rate_limit_definition = RATE_LIMIT_DEFINITIONS[RateLimitAction.chat_initiation]
872 with conversations_session(token) as c:
873 for _ in range(rate_limit_definition.warning_limit):
874 recipient, _ = generate_user()
875 c.SendDirectMessage(conversations_pb2.SendDirectMessageReq(recipient_user_id=recipient.id, text="hi"))
877 assert email_collector.count_for_reports() == 0
879 recipient, _ = generate_user()
880 existing_dm_recipient_id = recipient.id
881 c.SendDirectMessage(
882 conversations_pb2.SendDirectMessageReq(recipient_user_id=existing_dm_recipient_id, text="hi")
883 )
885 email = email_collector.pop_for_reports(last=True)
886 assert email.plain.startswith(
887 f"User {user.username} has sent {rate_limit_definition.warning_limit} chat initiations in the past {RATE_LIMIT_HOURS} hours."
888 )
890 for _ in range(rate_limit_definition.hard_limit - rate_limit_definition.warning_limit - 1):
891 recipient, _ = generate_user()
892 c.SendDirectMessage(conversations_pb2.SendDirectMessageReq(recipient_user_id=recipient.id, text="hi"))
894 assert email_collector.count_for_reports() == 0
896 # follow-up into an existing DM must not count as a new initiation
897 c.SendDirectMessage(
898 conversations_pb2.SendDirectMessageReq(recipient_user_id=existing_dm_recipient_id, text="follow-up")
899 )
900 assert email_collector.count_for_reports() == 0
902 recipient, _ = generate_user()
903 with pytest.raises(grpc.RpcError) as exc_info:
904 c.SendDirectMessage(conversations_pb2.SendDirectMessageReq(recipient_user_id=recipient.id, text="hi"))
905 assert exc_info.value.code() == grpc.StatusCode.RESOURCE_EXHAUSTED
906 assert (
907 exc_info.value.details()
908 == "You have messaged a lot of users in the past 24 hours. To avoid spam, you can't contact any more users for now."
909 )
911 email = email_collector.pop_for_reports(last=True)
912 assert email.plain.startswith(
913 f"User {user.username} has sent {rate_limit_definition.hard_limit} chat initiations in the past {RATE_LIMIT_HOURS} hours."
914 )
915 assert "The user has been blocked from sending further chat initiations for now." in email.plain
918def test_leave_invite_to_group_chat(db, moderator):
919 user1, token1 = generate_user()
920 user2, token2 = generate_user()
921 user3, token3 = generate_user()
922 user4, token4 = generate_user()
923 user5, token5 = generate_user()
924 user6, token6 = generate_user(delete_user=True)
925 user7, token7 = generate_user()
926 user8, token8 = generate_user()
928 make_friends(user1, user2)
929 make_friends(user1, user3)
930 make_friends(user1, user5)
931 make_friends(user1, user7)
932 make_friends(user1, user8)
933 make_friends(user2, user3)
934 make_friends(user4, user3)
935 make_user_block(user1, user7)
936 make_user_block(user8, user1)
938 with conversations_session(token1) as c:
939 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user5.id]))
940 group_chat_id = res.group_chat_id
941 moderator.approve_group_chat(group_chat_id)
942 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
944 # other user not in chat
945 with conversations_session(token3) as c:
946 with pytest.raises(grpc.RpcError) as e:
947 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
948 assert e.value.code() == grpc.StatusCode.NOT_FOUND
949 with pytest.raises(grpc.RpcError) as e:
950 res = c.InviteToGroupChat(
951 conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user4.id)
952 )
953 assert e.value.code() == grpc.StatusCode.NOT_FOUND
954 with pytest.raises(grpc.RpcError) as e:
955 res = c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
956 assert e.value.code() == grpc.StatusCode.NOT_FOUND
958 with conversations_session(token2) as c:
959 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
960 assert user3.id not in res.member_user_ids
962 # only_admins_invite defaults to true so shouldn't be able to invite
963 with pytest.raises(grpc.RpcError) as e:
964 res = c.InviteToGroupChat(
965 conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id)
966 )
967 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED
968 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
970 with conversations_session(token1) as c:
971 # invite invisible user fails
972 with pytest.raises(grpc.RpcError) as e:
973 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user6.id))
974 assert e.value.code() == grpc.StatusCode.NOT_FOUND
975 assert e.value.details() == "Couldn't find that user."
976 # invite fake user fails
977 with pytest.raises(grpc.RpcError) as e:
978 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=999))
979 assert e.value.code() == grpc.StatusCode.NOT_FOUND
980 assert e.value.details() == "Couldn't find that user."
981 # invite blocked user fails
982 with pytest.raises(grpc.RpcError) as e:
983 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user7.id))
984 assert e.value.code() == grpc.StatusCode.NOT_FOUND
985 assert e.value.details() == "Couldn't find that user."
986 # invite blocking user fails
987 with pytest.raises(grpc.RpcError) as e:
988 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user8.id))
989 assert e.value.code() == grpc.StatusCode.NOT_FOUND
990 assert e.value.details() == "Couldn't find that user."
992 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id))
993 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
994 assert user1.id in res.member_user_ids
995 assert user5.id in res.member_user_ids
996 assert user3.id in res.member_user_ids
998 # test non-admin inviting
999 c.EditGroupChat(
1000 conversations_pb2.EditGroupChatReq(
1001 group_chat_id=group_chat_id, only_admins_invite=wrappers_pb2.BoolValue(value=False)
1002 )
1003 )
1005 with conversations_session(token3) as c:
1006 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user2.id))
1007 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
1008 assert user2.id in res.member_user_ids
1011def test_group_chats_with_messages_before_join(db, moderator):
1012 """
1013 If user 1 and 2 have a group chat and send messages, then add user 3; user 3
1014 should still see the group chat!
1015 """
1016 user1, token1 = generate_user()
1017 user2, token2 = generate_user()
1018 user3, token3 = generate_user()
1019 user4, token4 = generate_user()
1021 make_friends(user1, user2)
1022 make_friends(user1, user3)
1023 make_friends(user2, user3)
1024 make_friends(user1, user4)
1026 with conversations_session(token1) as c:
1027 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user4.id]))
1028 group_chat_id = res.group_chat_id
1029 moderator.approve_group_chat(group_chat_id)
1030 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
1032 with conversations_session(token2) as c:
1033 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 2"))
1035 with conversations_session(token1) as c:
1036 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 3"))
1038 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id))
1040 with conversations_session(token3) as c:
1041 # should work
1042 c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id))
1044 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
1045 assert len(res.group_chats) == 1
1048def test_invite_to_dm(db):
1049 user1, token1 = generate_user()
1050 user2, token2 = generate_user()
1051 user3, token3 = generate_user()
1053 make_friends(user1, user2)
1054 make_friends(user1, user3)
1055 make_friends(user2, user3)
1057 with conversations_session(token1) as c:
1058 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
1059 group_chat_id = res.group_chat_id
1060 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
1062 # dm, shou;dn't be able to invite someone else
1063 with pytest.raises(grpc.RpcError) as e:
1064 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id))
1065 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1066 assert e.value.details() == "You can't invite other users to a direct message."
1069def test_sole_admin_leaves(db, moderator):
1070 user1, token1 = generate_user()
1071 user2, token2 = generate_user()
1072 user3, token3 = generate_user()
1074 make_friends(user1, user2)
1075 make_friends(user1, user3)
1076 make_friends(user2, user3)
1078 with conversations_session(token1) as c:
1079 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
1080 group_chat_id = res.group_chat_id
1081 moderator.approve_group_chat(group_chat_id)
1082 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
1084 # sole admin can't leave group chat
1085 with pytest.raises(grpc.RpcError) as e:
1086 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
1087 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1088 assert e.value.details() == "The last admin can't leave a group chat."
1090 with conversations_session(token2) as c:
1091 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
1093 with conversations_session(token3) as c:
1094 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
1096 # sole admin can leave when last in chat
1097 with conversations_session(token1) as c:
1098 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
1101def test_search_messages(db, moderator):
1102 user1, token1 = generate_user()
1103 user2, token2 = generate_user()
1104 user3, token3 = generate_user()
1106 make_friends(user1, user2)
1107 make_friends(user1, user3)
1109 with conversations_session(token1) as c:
1110 # create some threads with messages
1111 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
1112 gc1_id = res.group_chat_id
1113 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gc1_id, text="Test message 1"))
1114 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gc1_id, text="Test message 2"))
1115 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
1116 gc2_id = res.group_chat_id
1117 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gc2_id, text="Test group message 3"))
1118 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gc2_id, text="Test group message 4"))
1120 # Approve group chats so they appear in search results
1121 moderator.approve_group_chat(gc1_id)
1122 moderator.approve_group_chat(gc2_id)
1124 with conversations_session(token1) as c:
1125 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="message "))
1126 assert len(res.results) == 4
1127 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="group "))
1128 assert len(res.results) == 2
1129 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="message 5"))
1130 assert len(res.results) == 0
1132 # outside user doesn't get results
1133 with conversations_session(token3) as c:
1134 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="Test message"))
1135 assert len(res.results) == 0
1138def test_search_messages_left_joined(db, moderator):
1139 user1, token1 = generate_user()
1140 user2, token2 = generate_user()
1141 user3, token3 = generate_user()
1142 user4, token4 = generate_user()
1143 make_friends(user1, user2)
1144 make_friends(user1, user3)
1145 make_friends(user1, user4)
1147 with conversations_session(token1) as c:
1148 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user4.id]))
1149 group_chat_id = res.group_chat_id
1150 moderator.approve_group_chat(group_chat_id)
1151 for i in range(10):
1152 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message " + str(i)))
1154 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id))
1155 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 10"))
1156 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="Test message"))
1158 assert len(res.results) == 11
1160 with conversations_session(token3) as c:
1161 # can only see last message after invited
1162 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="Test message"))
1164 assert len(res.results) == 1
1165 assert res.results[0].message.text.text == "Test message 10"
1167 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
1169 with conversations_session(token1) as c:
1170 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 11"))
1171 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 12"))
1172 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id))
1173 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 13"))
1174 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 14"))
1176 with conversations_session(token3) as c:
1177 # can only see last message after invited
1178 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="Test message"))
1179 assert len(res.results) == 3
1180 assert res.results[0].message.text.text == "Test message 14"
1181 assert res.results[1].message.text.text == "Test message 13"
1182 assert res.results[2].message.text.text == "Test message 10"
1185def test_admin_behaviour(db, moderator):
1186 user1, token1 = generate_user()
1187 user2, token2 = generate_user()
1188 user3, token3 = generate_user()
1190 make_friends(user1, user2)
1191 make_friends(user1, user3)
1192 make_friends(user2, user3)
1194 with conversations_session(token1) as c:
1195 gcid = c.CreateGroupChat(
1196 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])
1197 ).group_chat_id
1198 moderator.approve_group_chat(gcid)
1199 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user2.id))
1200 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1201 assert len(res.admin_user_ids) == 2
1202 assert user1.id in res.admin_user_ids
1203 assert user2.id in res.admin_user_ids
1205 with conversations_session(token3) as c:
1206 with pytest.raises(grpc.RpcError) as e:
1207 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id))
1208 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED
1209 with pytest.raises(grpc.RpcError) as e:
1210 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user1.id))
1211 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED
1212 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1213 assert len(res.admin_user_ids) == 2
1214 assert user1.id in res.admin_user_ids
1215 assert user2.id in res.admin_user_ids
1217 with conversations_session(token2) as c:
1218 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id))
1219 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1220 assert len(res.admin_user_ids) == 3
1221 assert user1.id in res.admin_user_ids
1222 assert user2.id in res.admin_user_ids
1223 assert user3.id in res.admin_user_ids
1225 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user1.id))
1226 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1227 assert len(res.admin_user_ids) == 2
1228 assert user2.id in res.admin_user_ids
1229 assert user3.id in res.admin_user_ids
1231 with conversations_session(token1) as c:
1232 with pytest.raises(grpc.RpcError):
1233 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user1.id))
1234 with pytest.raises(grpc.RpcError):
1235 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id))
1236 with pytest.raises(grpc.RpcError):
1237 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user2.id))
1238 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1239 assert len(res.admin_user_ids) == 2
1240 assert user2.id in res.admin_user_ids
1241 assert user3.id in res.admin_user_ids
1243 with conversations_session(token2) as c:
1244 # can demote self if there are other admins
1245 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user2.id))
1246 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1247 assert len(res.admin_user_ids) == 1
1248 assert user3.id in res.admin_user_ids
1250 with conversations_session(token3) as c:
1251 with pytest.raises(grpc.RpcError) as e:
1252 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id))
1253 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1254 assert e.value.details() == "You can't remove the last admin."
1255 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1256 assert len(res.admin_user_ids) == 1
1257 assert user3.id in res.admin_user_ids
1259 # last admin can't leave
1260 with pytest.raises(grpc.RpcError) as e:
1261 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid))
1262 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1263 assert e.value.details() == "The last admin can't leave a group chat."
1265 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user1.id))
1267 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid))
1269 with conversations_session(token2) as c:
1270 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid))
1272 # last participant must be admin but can leave to orphan chat
1273 with conversations_session(token1) as c:
1274 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid))
1277def test_add_remove_admin_failures(db):
1278 user1, token1 = generate_user()
1279 user2, token2 = generate_user()
1280 user3, token3 = generate_user()
1281 user4, token4 = generate_user()
1282 user5, token5 = generate_user()
1284 make_friends(user1, user2)
1285 make_friends(user1, user3)
1286 make_friends(user1, user4)
1287 make_friends(user1, user5)
1289 with conversations_session(token1) as c:
1290 gcid = c.CreateGroupChat(
1291 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id, user4.id, user5.id])
1292 ).group_chat_id
1294 make_user_invisible(user3.id)
1295 make_user_block(user1, user4)
1296 make_user_block(user5, user1)
1298 # make non-existent user admin
1299 with pytest.raises(grpc.RpcError) as e:
1300 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=999))
1301 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1302 assert e.value.details() == "Couldn't find that user."
1304 # make invisible user admin
1305 with pytest.raises(grpc.RpcError) as e:
1306 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id))
1307 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1308 assert e.value.details() == "Couldn't find that user."
1310 # make blocked user admin
1311 with pytest.raises(grpc.RpcError) as e:
1312 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user4.id))
1313 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1314 assert e.value.details() == "Couldn't find that user."
1316 # make blocking user admin
1317 with pytest.raises(grpc.RpcError) as e:
1318 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user5.id))
1319 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1320 assert e.value.details() == "Couldn't find that user."
1322 with session_scope() as session:
1323 subscriptions = (
1324 session.execute(
1325 select(GroupChatSubscription)
1326 .where(GroupChatSubscription.group_chat_id == gcid)
1327 .where(GroupChatSubscription.role == GroupChatRole.participant)
1328 )
1329 .scalars()
1330 .all()
1331 )
1333 for subscription in subscriptions:
1334 subscription.role = GroupChatRole.admin
1336 with conversations_session(token1) as c:
1337 # remove non-existent user admin
1338 with pytest.raises(grpc.RpcError) as e:
1339 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=999))
1340 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1341 assert e.value.details() == "Couldn't find that user."
1343 # remove invisible admin
1344 with pytest.raises(grpc.RpcError) as e:
1345 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id))
1346 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1347 assert e.value.details() == "Couldn't find that user."
1349 # remove blocked admin
1350 with pytest.raises(grpc.RpcError) as e:
1351 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user4.id))
1352 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1353 assert e.value.details() == "Couldn't find that user."
1355 # remove blocking admin
1356 with pytest.raises(grpc.RpcError) as e:
1357 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user5.id))
1358 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1359 assert e.value.details() == "Couldn't find that user."
1362def test_last_seen(db, moderator):
1363 user1, token1 = generate_user()
1364 user2, token2 = generate_user()
1365 user3, token3 = generate_user()
1367 make_friends(user1, user2)
1368 make_friends(user1, user3)
1369 make_friends(user2, user3)
1371 with conversations_session(token3) as c:
1372 # this is just here to mess up any issues we get if we pretend there's only one group chat ever
1373 gcid_distraction = c.CreateGroupChat(
1374 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user1.id])
1375 ).group_chat_id
1376 moderator.approve_group_chat(gcid_distraction)
1378 with conversations_session(token1) as c:
1379 gcid = c.CreateGroupChat(
1380 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])
1381 ).group_chat_id
1382 moderator.approve_group_chat(gcid)
1384 message_ids = []
1386 for i in range(6):
1387 c.SendMessage(
1388 conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text=f"gibberish message... {i}")
1389 )
1390 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text=f"test message {i}"))
1391 c.SendMessage(
1392 conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text=f"gibberish message {i}")
1393 )
1395 message_ids.append(
1396 c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)).latest_message.message_id
1397 )
1399 # messages are automatically marked as seen when you send a new message
1400 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1401 assert res.unseen_message_count == 0
1403 with conversations_session(token2) as c:
1404 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1405 # created + 6 normal
1406 assert res.unseen_message_count == 7
1408 backward_offset = 3
1409 c.MarkLastSeenGroupChat(
1410 conversations_pb2.MarkLastSeenGroupChatReq(
1411 group_chat_id=gcid, last_seen_message_id=message_ids[-backward_offset - 1]
1412 )
1413 )
1415 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1416 assert res.unseen_message_count == backward_offset
1418 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="test message ..."))
1420 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1421 assert res.unseen_message_count == 0
1423 with conversations_session(token3) as c:
1424 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1425 # created + 7 normal
1426 assert res.unseen_message_count == 8
1428 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="test message ..."))
1430 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1431 assert res.unseen_message_count == 0
1434def test_mark_last_seen_clears_notifications(db, moderator):
1435 user1, token1 = generate_user()
1436 user2, token2 = generate_user()
1438 with conversations_session(token1) as c:
1439 gcid = c.CreateGroupChat(
1440 conversations_pb2.CreateGroupChatReq(
1441 recipient_user_ids=[user2.id], title=wrappers_pb2.StringValue(value="Test chat")
1442 )
1443 ).group_chat_id
1445 moderator.approve_group_chat(gcid)
1447 with conversations_session(token1) as c:
1448 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello"))
1450 process_jobs()
1452 def unseen_notification_count(user_id):
1453 with session_scope() as session:
1454 return session.execute(
1455 select(func.count())
1456 .select_from(Notification)
1457 .where(Notification.user_id == user_id)
1458 .where(Notification.key == str(gcid))
1459 .where(Notification.is_seen == False)
1460 ).scalar_one()
1462 assert unseen_notification_count(user2.id) > 0
1464 with conversations_session(token2) as c:
1465 c.MarkLastSeenGroupChat(conversations_pb2.MarkLastSeenGroupChatReq(group_chat_id=gcid, last_seen_message_id=1))
1467 assert unseen_notification_count(user2.id) == 0
1470def test_mark_last_seen_clears_missed_messages_notification(db, moderator):
1471 """
1472 Regression test: chat__missed_messages is a summary keyed with "" rather than a chat id, so it
1473 needs to be marked seen separately from the per-chat chat__message notifications.
1474 """
1475 user1, token1 = generate_user()
1476 user2, token2 = generate_user()
1478 # this notification is email-only by default, and the in-app feed only shows push-enabled ones
1479 with notifications_session(token2) as n:
1480 n.SetNotificationSettings(
1481 notifications_pb2.SetNotificationSettingsReq(
1482 preferences=[
1483 notifications_pb2.SingleNotificationPreference(
1484 topic=NotificationTopicAction.chat__missed_messages.topic,
1485 action=NotificationTopicAction.chat__missed_messages.action,
1486 delivery_method="push",
1487 enabled=True,
1488 )
1489 ]
1490 )
1491 )
1493 with conversations_session(token1) as c:
1494 gcid = c.CreateGroupChat(
1495 conversations_pb2.CreateGroupChatReq(
1496 recipient_user_ids=[user2.id], title=wrappers_pb2.StringValue(value="Test chat")
1497 )
1498 ).group_chat_id
1500 moderator.approve_group_chat(gcid)
1502 with conversations_session(token1) as c:
1503 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello!"))
1505 # the job only picks up messages that have been unseen for five minutes
1506 with patch("couchers.jobs.handlers.now", now_5_min_in_future):
1507 send_message_notifications(empty_pb2.Empty())
1508 process_jobs()
1510 def unseen_missed_messages():
1511 with notifications_session(token2) as n:
1512 res = n.ListNotifications(notifications_pb2.ListNotificationsReq(only_unread=True))
1513 return [
1514 notification
1515 for notification in res.notifications
1516 if notification.topic == NotificationTopicAction.chat__missed_messages.topic
1517 and notification.action == NotificationTopicAction.chat__missed_messages.action
1518 ]
1520 assert len(unseen_missed_messages()) == 1
1522 with conversations_session(token2) as c:
1523 c.MarkLastSeenGroupChat(conversations_pb2.MarkLastSeenGroupChatReq(group_chat_id=gcid, last_seen_message_id=1))
1525 assert unseen_missed_messages() == []
1528def test_one_dm_per_pair(db, moderator):
1529 user1, token1 = generate_user()
1530 user2, token2 = generate_user()
1531 user3, token3 = generate_user()
1533 make_friends(user1, user2)
1534 make_friends(user1, user3)
1535 make_friends(user2, user3)
1537 with conversations_session(token1) as c:
1538 # create DM with user 2
1539 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
1540 assert res.is_dm
1541 dm_with_user2 = res.group_chat_id
1543 # create DM with user 3
1544 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id]))
1545 assert res.is_dm
1546 dm_with_user3 = res.group_chat_id
1548 # can't create another group chat with just user 2
1549 with pytest.raises(grpc.RpcError) as e:
1550 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
1551 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1553 # can't create another group chat with just user 3
1554 with pytest.raises(grpc.RpcError) as e:
1555 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id]))
1556 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1558 # can create joined group chat
1559 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
1560 assert not res.is_dm
1562 # Approve the DMs so user2 can see them (otherwise they're SHADOWED and only visible to creator)
1563 moderator.approve_group_chat(dm_with_user2)
1565 with conversations_session(token2) as c:
1566 # can create DM with user 3
1567 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id]))
1568 assert res.is_dm
1570 # can't create another group chat with just user 1 (DM was approved, so user2 can see it)
1571 with pytest.raises(grpc.RpcError) as e:
1572 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user1.id]))
1573 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1576def test_GetDirectMessage(db):
1577 user1, token1 = generate_user()
1578 user2, token2 = generate_user()
1579 user3, token3 = generate_user()
1581 make_friends(user1, user2)
1582 make_friends(user1, user3)
1583 make_friends(user2, user3)
1585 with conversations_session(token1) as c:
1586 # no group chat with user 2
1587 with pytest.raises(grpc.RpcError) as e:
1588 res = c.GetDirectMessage(conversations_pb2.GetDirectMessageReq(user_id=user2.id))
1589 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1591 # no group chat with nor user 3
1592 with pytest.raises(grpc.RpcError) as e:
1593 res = c.GetDirectMessage(conversations_pb2.GetDirectMessageReq(user_id=user3.id))
1594 assert e.value.code() == grpc.StatusCode.NOT_FOUND
1596 # create DM with user 2
1597 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
1598 assert res.is_dm
1599 gcid = res.group_chat_id
1601 # now should exist
1602 res = c.GetDirectMessage(conversations_pb2.GetDirectMessageReq(user_id=user2.id))
1603 assert res.group_chat_id == gcid
1604 assert not res.is_archived
1606 # create DM with user 3
1607 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id]))
1608 assert res.is_dm
1610 # can create joined group chat
1611 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]))
1612 assert not res.is_dm
1614 with conversations_session(token2) as c:
1615 # can create DM with user 3
1616 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id]))
1617 assert res.is_dm
1618 assert res.can_message
1619 gcid = res.group_chat_id
1621 # DM with 3 should exist, but can't message after being blocked
1622 make_user_block(user3, user2)
1623 res = c.GetDirectMessage(conversations_pb2.GetDirectMessageReq(user_id=user3.id))
1624 assert res.group_chat_id == gcid
1625 assert not res.can_message
1628def test_total_unseen(db, moderator):
1629 user1, token1 = generate_user()
1630 user2, token2 = generate_user()
1631 user3, token3 = generate_user()
1633 # distractions
1634 user4, token4 = generate_user()
1636 make_friends(user1, user2)
1637 make_friends(user1, user3)
1638 make_friends(user2, user3)
1640 # distractions
1641 make_friends(user1, user4)
1643 with conversations_session(token1) as c:
1644 # distractions
1645 gcid_distraction = c.CreateGroupChat(
1646 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user4.id])
1647 ).group_chat_id
1648 moderator.approve_group_chat(gcid_distraction)
1649 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction..."))
1651 gcid = c.CreateGroupChat(
1652 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])
1653 ).group_chat_id
1654 moderator.approve_group_chat(gcid)
1656 for i in range(6):
1657 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text=f"test message {i}"))
1659 # distractions
1660 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction..."))
1662 # messages are automatically marked as seen when you send a new message
1663 with api_session(token1) as api:
1664 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 0
1666 with api_session(token2) as api:
1667 # chat created + 6 normal messages
1668 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 7
1670 # now leave chat with user2
1671 with conversations_session(token2) as c:
1672 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid))
1674 with api_session(token2) as api:
1675 # seen messages becomes 0 when leaving
1676 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 0
1678 with conversations_session(token1) as c:
1679 # distractions
1680 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction..."))
1682 # send more stuff without user 2
1683 for i in range(3):
1684 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text=f"test message {i}"))
1686 # distractions
1687 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction..."))
1689 with api_session(token2) as api:
1690 # seen messages becomes 0 when leaving
1691 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 0
1693 with conversations_session(token1) as c:
1694 # add user 2 back
1695 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=gcid, user_id=user2.id))
1697 # send more stuff with user 2
1698 for i in range(12):
1699 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text=f"test message {i}"))
1701 # distractions
1702 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction..."))
1704 with api_session(token2) as api:
1705 # joined + 12 normal
1706 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 13
1709def test_regression_ListGroupChats_pagination(db, moderator):
1710 user1, token1 = generate_user()
1711 user2, token2 = generate_user()
1712 user3, token3 = generate_user()
1714 make_friends(user1, user2)
1715 make_friends(user1, user3)
1717 with conversations_session(token1) as c:
1718 # tuples of (group_chat_id, message_id)
1719 group_chat_and_message_ids = []
1720 for i in range(50):
1721 res1 = c.CreateGroupChat(
1722 conversations_pb2.CreateGroupChatReq(
1723 recipient_user_ids=[user2.id, user3.id], title=wrappers_pb2.StringValue(value=f"Chat {i}")
1724 )
1725 )
1727 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res1.group_chat_id, text=f"Test message {i}"))
1729 res2 = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=res1.group_chat_id))
1731 group_chat_and_message_ids.append((res2.group_chat_id, res2.latest_message.message_id))
1732 moderator.approve_group_chat(res1.group_chat_id)
1734 seen_group_chat_ids = []
1736 last_message_id = 0
1737 more = True
1738 while more:
1739 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(last_message_id=last_message_id))
1740 last_message_id = res.last_message_id
1741 more = not res.no_more
1743 seen_group_chat_ids.extend([chat.group_chat_id for chat in res.group_chats])
1745 assert set(seen_group_chat_ids) == {x[0] for x in group_chat_and_message_ids}, "Not all group chats returned"
1748def test_muting(db, moderator):
1749 user1, token1 = generate_user()
1750 user2, token2 = generate_user()
1751 user3, token3 = generate_user()
1753 make_friends(user1, user2)
1754 make_friends(user1, user3)
1755 make_friends(user2, user3)
1757 with conversations_session(token3) as c:
1758 # this is just here to mess up any issues we get if we pretend there's only one group chat ever
1759 gcid_distraction = c.CreateGroupChat(
1760 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user1.id])
1761 ).group_chat_id
1762 moderator.approve_group_chat(gcid_distraction)
1764 with conversations_session(token1) as c:
1765 gcid = c.CreateGroupChat(
1766 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])
1767 ).group_chat_id
1768 moderator.approve_group_chat(gcid)
1770 with conversations_session(token2) as c:
1771 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1772 assert not res.mute_info.muted
1773 assert not res.mute_info.HasField("muted_until")
1775 c.MuteGroupChat(conversations_pb2.MuteGroupChatReq(group_chat_id=gcid, forever=True))
1776 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1777 assert res.mute_info.muted
1778 assert not res.mute_info.HasField("muted_until")
1780 c.MuteGroupChat(conversations_pb2.MuteGroupChatReq(group_chat_id=gcid, unmute=True))
1781 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1782 assert not res.mute_info.muted
1783 assert not res.mute_info.HasField("muted_until")
1785 c.MuteGroupChat(
1786 conversations_pb2.MuteGroupChatReq(
1787 group_chat_id=gcid, for_duration=Duration_from_timedelta(timedelta(hours=2))
1788 )
1789 )
1790 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1791 assert res.mute_info.muted
1792 assert res.mute_info.HasField("muted_until")
1793 assert to_aware_datetime(res.mute_info.muted_until) >= now() + timedelta(hours=1, minutes=59)
1794 assert to_aware_datetime(res.mute_info.muted_until) <= now() + timedelta(hours=2, minutes=1)
1797def test_archiving(db, moderator):
1798 """Test SetGroupChatArchiveStatus RPC with GetGroupChat and ListGroupChats"""
1799 user1, token1 = generate_user()
1800 user2, token2 = generate_user()
1801 user3, token3 = generate_user()
1803 make_friends(user1, user2)
1804 make_friends(user1, user3)
1805 make_friends(user2, user3)
1807 # Create a distraction chat to ensure we're testing the right one
1808 with conversations_session(token3) as c:
1809 gcid_distraction = c.CreateGroupChat(
1810 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user1.id])
1811 ).group_chat_id
1812 moderator.approve_group_chat(gcid_distraction)
1814 with conversations_session(token1) as c:
1815 gcid = c.CreateGroupChat(
1816 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])
1817 ).group_chat_id
1818 moderator.approve_group_chat(gcid)
1820 # Test basic archive/unarchive functionality
1821 with conversations_session(token2) as c:
1822 # Initially not archived
1823 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1824 assert not res.is_archived
1826 # Archive the chat
1827 archive_res = c.SetGroupChatArchiveStatus(
1828 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
1829 )
1830 assert archive_res.group_chat_id == gcid
1831 assert archive_res.is_archived
1833 # Verify archived via GetGroupChat
1834 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1835 assert res.is_archived
1837 # Unarchive the chat
1838 archive_res = c.SetGroupChatArchiveStatus(
1839 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False)
1840 )
1841 assert archive_res.group_chat_id == gcid
1842 assert not archive_res.is_archived
1844 # Verify unarchived via GetGroupChat
1845 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1846 assert not res.is_archived
1849def test_archiving_per_user(db, moderator):
1850 """Test that archiving is per-user - one user archiving doesn't affect others"""
1851 user1, token1 = generate_user()
1852 user2, token2 = generate_user()
1854 make_friends(user1, user2)
1856 with conversations_session(token1) as c:
1857 gcid = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id
1858 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello"))
1859 moderator.approve_group_chat(gcid)
1861 # User1 archives the chat
1862 with conversations_session(token1) as c:
1863 c.SetGroupChatArchiveStatus(
1864 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
1865 )
1866 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1867 assert res.is_archived
1869 # User2 should NOT see it as archived
1870 with conversations_session(token2) as c:
1871 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1872 assert not res.is_archived
1874 # User2 archives it too
1875 with conversations_session(token2) as c:
1876 c.SetGroupChatArchiveStatus(
1877 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
1878 )
1879 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1880 assert res.is_archived
1882 # User1 unarchives - user2 should still see it as archived
1883 with conversations_session(token1) as c:
1884 c.SetGroupChatArchiveStatus(
1885 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False)
1886 )
1887 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1888 assert not res.is_archived
1890 with conversations_session(token2) as c:
1891 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
1892 assert res.is_archived
1895def test_archiving_with_list_group_chats(db, moderator):
1896 """Test archive filtering with ListGroupChats endpoint"""
1897 user1, token1 = generate_user()
1898 user2, token2 = generate_user()
1899 user3, token3 = generate_user()
1901 make_friends(user1, user2)
1902 make_friends(user1, user3)
1904 with conversations_session(token1) as c:
1905 # Create 3 chats
1906 gcid1 = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id
1907 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid1, text="Chat 1"))
1908 moderator.approve_group_chat(gcid1)
1910 gcid2 = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id])).group_chat_id
1911 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid2, text="Chat 2"))
1912 moderator.approve_group_chat(gcid2)
1914 gcid3 = c.CreateGroupChat(
1915 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])
1916 ).group_chat_id
1917 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid3, text="Chat 3"))
1918 moderator.approve_group_chat(gcid3)
1920 with conversations_session(token1) as c:
1921 # Initially all 3 chats should be visible
1922 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
1923 assert len(res.group_chats) == 3
1925 # All should be non-archived
1926 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False))
1927 assert len(res.group_chats) == 3
1929 # None should be archived
1930 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True))
1931 assert len(res.group_chats) == 0
1933 # Archive chat 1
1934 c.SetGroupChatArchiveStatus(
1935 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid1, is_archived=True)
1936 )
1938 # Without filter, still see all 3
1939 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq())
1940 assert len(res.group_chats) == 3
1942 # Non-archived should show 2
1943 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False))
1944 assert len(res.group_chats) == 2
1945 assert gcid1 not in [gc.group_chat_id for gc in res.group_chats]
1947 # Archived should show 1
1948 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True))
1949 assert len(res.group_chats) == 1
1950 assert res.group_chats[0].group_chat_id == gcid1
1951 assert res.group_chats[0].is_archived
1953 # Archive chat 2 as well
1954 c.SetGroupChatArchiveStatus(
1955 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid2, is_archived=True)
1956 )
1958 # Non-archived should show 1
1959 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False))
1960 assert len(res.group_chats) == 1
1961 assert res.group_chats[0].group_chat_id == gcid3
1963 # Archived should show 2
1964 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True))
1965 assert len(res.group_chats) == 2
1966 archived_ids = {gc.group_chat_id for gc in res.group_chats}
1967 assert archived_ids == {gcid1, gcid2}
1969 # Unarchive chat 1
1970 c.SetGroupChatArchiveStatus(
1971 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid1, is_archived=False)
1972 )
1974 # Non-archived should show 2
1975 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False))
1976 assert len(res.group_chats) == 2
1978 # Archived should show 1
1979 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True))
1980 assert len(res.group_chats) == 1
1981 assert res.group_chats[0].group_chat_id == gcid2
1984def test_archiving_chat_not_found(db, moderator):
1985 """Test that archiving a non-existent or non-accessible chat fails"""
1986 user1, token1 = generate_user()
1987 user2, token2 = generate_user()
1988 user3, token3 = generate_user()
1990 make_friends(user1, user2)
1992 with conversations_session(token1) as c:
1993 gcid = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id
1994 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello"))
1995 moderator.approve_group_chat(gcid)
1997 # User3 is not in the chat - should get NOT_FOUND
1998 with conversations_session(token3) as c:
1999 with pytest.raises(grpc.RpcError) as e:
2000 c.SetGroupChatArchiveStatus(
2001 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
2002 )
2003 assert e.value.code() == grpc.StatusCode.NOT_FOUND
2005 # Non-existent chat ID should fail
2006 with conversations_session(token1) as c:
2007 with pytest.raises(grpc.RpcError) as e:
2008 c.SetGroupChatArchiveStatus(
2009 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=99999, is_archived=True)
2010 )
2011 assert e.value.code() == grpc.StatusCode.NOT_FOUND
2014def test_archiving_after_leaving_chat(db, moderator):
2015 """Test that you can't archive a chat after leaving it"""
2016 user1, token1 = generate_user()
2017 user2, token2 = generate_user()
2018 user3, token3 = generate_user()
2020 make_friends(user1, user2)
2021 make_friends(user1, user3)
2022 make_friends(user2, user3)
2024 with conversations_session(token1) as c:
2025 gcid = c.CreateGroupChat(
2026 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])
2027 ).group_chat_id
2028 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello"))
2029 moderator.approve_group_chat(gcid)
2031 # User2 leaves the chat
2032 with conversations_session(token2) as c:
2033 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid))
2035 # User2 should not be able to archive it now
2036 with conversations_session(token2) as c:
2037 with pytest.raises(grpc.RpcError) as e:
2038 c.SetGroupChatArchiveStatus(
2039 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
2040 )
2041 assert e.value.code() == grpc.StatusCode.NOT_FOUND
2044def test_archiving_dm(db, moderator):
2045 """Test that archiving works for DMs as well as group chats"""
2046 user1, token1 = generate_user()
2047 user2, token2 = generate_user()
2049 make_friends(user1, user2)
2051 with conversations_session(token1) as c:
2052 # Create a DM
2053 gcid = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id
2054 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello"))
2055 moderator.approve_group_chat(gcid)
2057 # Verify it's a DM
2058 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
2059 assert res.is_dm
2060 assert not res.is_archived
2062 # Archive the DM
2063 c.SetGroupChatArchiveStatus(
2064 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
2065 )
2067 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
2068 assert res.is_archived
2070 # Unarchive it
2071 c.SetGroupChatArchiveStatus(
2072 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False)
2073 )
2075 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
2076 assert not res.is_archived
2079def test_archiving_idempotent(db, moderator):
2080 """Test that archiving/unarchiving is idempotent"""
2081 user1, token1 = generate_user()
2082 user2, token2 = generate_user()
2084 make_friends(user1, user2)
2086 with conversations_session(token1) as c:
2087 gcid = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id
2088 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello"))
2089 moderator.approve_group_chat(gcid)
2091 # Archive twice - should work without error
2092 c.SetGroupChatArchiveStatus(
2093 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
2094 )
2095 c.SetGroupChatArchiveStatus(
2096 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True)
2097 )
2098 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
2099 assert res.is_archived
2101 # Unarchive twice - should work without error
2102 c.SetGroupChatArchiveStatus(
2103 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False)
2104 )
2105 c.SetGroupChatArchiveStatus(
2106 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False)
2107 )
2108 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid))
2109 assert not res.is_archived
2112def test_chat_notifications(db, moderator):
2113 user1, token1 = generate_user()
2114 user2, token2 = generate_user()
2115 # notifs off
2116 user3, token3 = generate_user()
2117 user4, token4 = generate_user()
2118 user5, token5 = generate_user()
2119 user6, token6 = generate_user()
2121 make_friends(user1, user2)
2122 make_friends(user1, user3)
2123 make_friends(user1, user4)
2124 make_friends(user4, user5)
2125 make_friends(user4, user6)
2127 # have some of them enable/disable notifs
2128 topic_action = NotificationTopicAction.chat__message
2129 for token, enabled in [
2130 (token1, True),
2131 (token2, True),
2132 (token3, False),
2133 (token4, True),
2134 (token5, True),
2135 (token6, True),
2136 ]:
2137 with notifications_session(token) as notifications:
2138 notifications.SetNotificationSettings(
2139 notifications_pb2.SetNotificationSettingsReq(
2140 preferences=[
2141 notifications_pb2.SingleNotificationPreference(
2142 topic=topic_action.topic,
2143 action=topic_action.action,
2144 delivery_method=delivery_method,
2145 enabled=enabled,
2146 )
2147 for delivery_method in ["push", "email", "digest"]
2148 ],
2149 )
2150 )
2152 group_chat_id = None
2154 def send_msg(c, i):
2155 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text=f"Test message {i}"))
2157 with conversations_session(token1) as c:
2158 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id, user4.id]))
2159 group_chat_id = res.group_chat_id
2160 moderator.approve_group_chat(group_chat_id)
2161 c.EditGroupChat(
2162 conversations_pb2.EditGroupChatReq(
2163 group_chat_id=group_chat_id, only_admins_invite=wrappers_pb2.BoolValue(value=False)
2164 )
2165 )
2166 send_msg(c, i=1)
2167 send_msg(c, i=2)
2169 with conversations_session(token4) as c:
2170 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user5.id))
2171 send_msg(c, i=3)
2172 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user6.id))
2173 send_msg(c, i=4)
2174 send_msg(c, i=5)
2176 with conversations_session(token3) as c:
2177 send_msg(c, i=6)
2178 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
2180 with conversations_session(token2) as c:
2181 send_msg(c, i=7)
2182 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id))
2184 with conversations_session(token6) as c:
2185 send_msg(c, i=8)
2187 # go through all bg jobs
2188 while process_job():
2189 pass
2191 # now check notifs...
2192 expected_notifs = [
2193 (user1, "user1", [3, 4, 5, 6, 7, 8]),
2194 (user2, "user2", [1, 2, 3, 4, 5, 6]),
2195 (user3, "user3", []), # notifs off
2196 (user4, "user4", [1, 2, 6, 7, 8]),
2197 (user5, "user5", [3, 4, 5, 6, 7, 8]),
2198 (user6, "user6", [4, 5, 6, 7]),
2199 ]
2201 with session_scope() as session:
2202 for user, label, expected_msgs in expected_notifs:
2203 deliv = (
2204 session.execute(
2205 select(Notification.data)
2206 .join(NotificationDelivery, NotificationDelivery.notification_id == Notification.id)
2207 .where(Notification.user_id == user.id)
2208 .where(Notification.topic_action == topic_action)
2209 .where(NotificationDelivery.delivery_type == NotificationDeliveryType.push)
2210 .order_by(Notification.created)
2211 )
2212 .scalars()
2213 .all()
2214 )
2216 def parse_message_payload(data):
2217 return notification_data_pb2.ChatMessage.FromString(data).text
2219 contents = [parse_message_payload(d) for d in deliv]
2221 print(contents)
2223 assert [f"Test message {i}" for i in expected_msgs] == contents, f"Wrong messages for {label}"
2226def test_incomplete_profile(db):
2227 user1, token1 = generate_user(complete_profile=True)
2228 user2, token2 = generate_user(complete_profile=False)
2229 user3, token3 = generate_user(complete_profile=True)
2230 make_friends(user1, user2)
2231 make_friends(user1, user3)
2233 # user 1 can make a chat
2234 with conversations_session(token1) as c:
2235 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id]))
2236 group_chat_id = res.group_chat_id
2237 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1"))
2238 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id))
2239 assert res.messages[0].text.text == "Test message 1"
2240 assert to_aware_datetime(res.messages[0].time) <= now()
2241 assert res.messages[0].author_user_id == user1.id
2243 # user 2 cannot
2244 with conversations_session(token2) as c:
2245 with pytest.raises(grpc.RpcError) as e:
2246 c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id]))
2247 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
2248 assert e.value.details() == "You have to complete your profile before you can send a message."