Coverage for app/backend/src/tests/test_conversations.py: 100%

1276 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-06-14 11:44 +0000

1from datetime import timedelta 

2 

3import grpc 

4import pytest 

5from google.protobuf import wrappers_pb2 

6from sqlalchemy import func, select 

7 

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 EmailCollector, PushCollector, process_jobs 

24from tests.fixtures.sessions import api_session, conversations_session, notifications_session 

25 

26 

27@pytest.fixture(autouse=True) 

28def _(testconfig): 

29 pass 

30 

31 

32def test_list_group_chats(db, moderator): 

33 user1, token1 = generate_user() 

34 user2, token2 = generate_user() 

35 user3, token3 = generate_user() 

36 

37 make_friends(user2, user1) 

38 make_friends(user1, user3) 

39 

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 

44 

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")) 

58 

59 moderator.approve_group_chat(group_chat1_id) 

60 moderator.approve_group_chat(group_chat2_id) 

61 

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 

66 

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 

71 

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 

76 

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 

84 

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 

89 

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 

93 

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 

97 

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 

102 

103 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True)) 

104 assert len(res.group_chats) == 0 

105 

106 

107def test_list_empty_group_chats(db, moderator): 

108 user1, token1 = generate_user() 

109 user2, token2 = generate_user() 

110 user3, token3 = generate_user() 

111 

112 make_friends(user1, user3) 

113 make_friends(user2, user1) 

114 make_friends(user2, user3) 

115 

116 with conversations_session(token1) as c: 

117 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq()) 

118 assert len(res.group_chats) == 0 

119 

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])) 

122 

123 moderator.approve_group_chat(res1.group_chat_id) 

124 moderator.approve_group_chat(res2.group_chat_id) 

125 

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 

130 

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 

135 

136 res3 = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id])) 

137 moderator.approve_group_chat(res3.group_chat_id) 

138 

139 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq()) 

140 assert len(res.group_chats) == 3 

141 assert res.no_more 

142 

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 

147 

148 

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() 

155 

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) 

162 

163 chat_ids = [] 

164 

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")) 

187 

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")) 

196 

197 for chat_id in chat_ids: 

198 moderator.approve_group_chat(chat_id) 

199 

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" 

215 

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 ) 

222 

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" 

232 

233 

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() 

242 

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) 

249 

250 chat_ids = [] 

251 

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")) 

276 

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")) 

285 

286 for chat_id in chat_ids: 

287 moderator.approve_group_chat(chat_id) 

288 

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")) 

297 

298 # leave chat 

299 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=left_chat_id)) 

300 

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")) 

304 

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" 

315 

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" 

325 

326 

327def test_get_group_chat_messages(db): 

328 user1, token1 = generate_user() 

329 user2, token2 = generate_user() 

330 user3, token3 = generate_user() 

331 

332 make_friends(user1, user2) 

333 

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")) 

340 

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 

345 

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" 

349 

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 

354 

355 

356def test_get_group_chat_messages_pagination(db, moderator): 

357 user1, token1 = generate_user() 

358 user2, token2 = generate_user() 

359 make_friends(user1, user2) 

360 

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))) 

366 

367 moderator.approve_group_chat(group_chat_id) 

368 

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 

385 

386 

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) 

395 

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) 

400 

401 for i in range(10): 

402 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text=str(i))) 

403 

404 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id)) 

405 

406 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="10")) 

407 

408 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id)) 

409 

410 # created + 10 normal + invited + normal 

411 assert len(res.messages) == 13 

412 

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" 

419 

420 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id)) 

421 

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")) 

425 

426 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id)) 

427 

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")) 

430 

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" 

442 

443 

444def test_get_group_chat_info(db): 

445 user1, token1 = generate_user() 

446 user2, token2 = generate_user() 

447 user3, token3 = generate_user() 

448 

449 make_friends(user1, user2) 

450 make_friends(user3, user1) 

451 

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 

466 

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 

475 

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 

485 

486 

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() 

492 

493 make_friends(user1, user2) 

494 make_friends(user3, user1) 

495 

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")) 

505 

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 

510 

511 

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() 

517 

518 make_friends(user1, user2) 

519 make_friends(user3, user1) 

520 make_friends(user1, user4) 

521 

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")) 

532 

533 with conversations_session(token3) as c: 

534 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id)) 

535 

536 with conversations_session(token1) as c: 

537 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user4.id)) 

538 

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 

547 

548 

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) 

556 

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 

566 

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 

570 

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 

577 

578 

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) 

584 

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) 

594 

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 

605 

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 

617 

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 

629 

630 

631def test_make_remove_group_chat_admin(db, moderator): 

632 user1, token1 = generate_user() 

633 user2, token2 = generate_user() 

634 user3, token3 = generate_user() 

635 

636 make_friends(user1, user2) 

637 make_friends(user1, user3) 

638 make_friends(user2, user3) 

639 

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) 

645 

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." 

653 

654 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=group_chat_id, user_id=user2.id)) 

655 

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." 

661 

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 

666 

667 with conversations_session(token1) as c: 

668 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=group_chat_id, user_id=user2.id)) 

669 

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 

673 

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 

679 

680 

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) 

687 

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 

696 

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 

702 

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." 

708 

709 

710def test_send_direct_message(db, moderator, push_collector: PushCollector): 

711 user1, token1 = generate_user(complete_profile=True) 

712 user2, token2 = generate_user(complete_profile=True) 

713 

714 make_friends(user1, user2) 

715 

716 message1 = "Hello, user2!" 

717 message2 = "One more message." 

718 

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) 

723 

724 c1.SendDirectMessage(conversations_pb2.SendDirectMessageReq(recipient_user_id=user2.id, text=message2)) 

725 

726 process_jobs() 

727 

728 push = push_collector.pop_for_user(user2.id, last=False) 

729 assert push.topic_action == NotificationTopicAction.chat__message.display 

730 assert push.content.title == user1.name 

731 assert push.content.body == message1 

732 

733 push = push_collector.pop_for_user(user2.id, last=True) 

734 assert push.topic_action == NotificationTopicAction.chat__message.display 

735 assert push.content.title == user1.name 

736 assert push.content.body == message2 

737 

738 with conversations_session(token2) as c2: 

739 # Fetch the chat by ID returned from SendDirectMessage 

740 chat = c2.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=res.group_chat_id)) 

741 

742 assert chat.is_dm 

743 group_chat_id = chat.group_chat_id 

744 

745 # Verify that the messages was received 

746 messages = c2.GetGroupChatMessages( 

747 conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id) 

748 ).messages 

749 

750 assert len(messages) == 2 

751 assert messages[0].text.text == message2 

752 assert messages[1].text.text == message1 

753 assert messages[0].author_user_id == user1.id 

754 

755 

756def test_excessive_chat_initiations_are_reported(db, email_collector: EmailCollector): 

757 """Test that excessive chat initiations are first reported in a warning email and finally lead blocking of further contacting other users.""" 

758 user, token = generate_user() 

759 rate_limit_definition = RATE_LIMIT_DEFINITIONS[RateLimitAction.chat_initiation] 

760 with conversations_session(token) as c: 

761 # Test warning email 

762 for _ in range(rate_limit_definition.warning_limit): 

763 recipient_user, _ = generate_user() 

764 _ = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[recipient_user.id])) 

765 

766 assert email_collector.count_for_reports() == 0 

767 

768 recipient_user, _ = generate_user() 

769 _ = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[recipient_user.id])) 

770 

771 email = email_collector.pop_for_reports(last=True) 

772 assert email.plain.startswith( 

773 f"User {user.username} has sent {rate_limit_definition.warning_limit} chat initiations in the past {RATE_LIMIT_HOURS} hours." 

774 ) 

775 

776 # Test new chat initiations fail after exceeding CHAT_INITIATION_HARD_LIMIT 

777 for _ in range(rate_limit_definition.hard_limit - rate_limit_definition.warning_limit - 1): 

778 recipient_user, _ = generate_user() 

779 _ = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[recipient_user.id])) 

780 

781 assert email_collector.count_for_reports() == 0 

782 

783 recipient_user, _ = generate_user() 

784 with pytest.raises(grpc.RpcError) as exc_info: 

785 _ = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[recipient_user.id])) 

786 assert exc_info.value.code() == grpc.StatusCode.RESOURCE_EXHAUSTED 

787 assert ( 

788 exc_info.value.details() 

789 == "You have messaged a lot of users in the past 24 hours. To avoid spam, you can't contact any more users for now." 

790 ) 

791 

792 email = email_collector.pop_for_reports(last=True) 

793 assert email.plain.startswith( 

794 f"User {user.username} has sent {rate_limit_definition.hard_limit} chat initiations in the past {RATE_LIMIT_HOURS} hours." 

795 ) 

796 assert "The user has been blocked from sending further chat initiations for now." in email.plain 

797 

798 

799def test_send_direct_message_rate_limit(db, moderator, email_collector: EmailCollector): 

800 """SendDirectMessage should enforce the chat_initiation rate limit when creating a new DM, but not when sending into an existing one.""" 

801 user, token = generate_user(complete_profile=True) 

802 rate_limit_definition = RATE_LIMIT_DEFINITIONS[RateLimitAction.chat_initiation] 

803 

804 with conversations_session(token) as c: 

805 for _ in range(rate_limit_definition.warning_limit): 

806 recipient, _ = generate_user() 

807 c.SendDirectMessage(conversations_pb2.SendDirectMessageReq(recipient_user_id=recipient.id, text="hi")) 

808 

809 assert email_collector.count_for_reports() == 0 

810 

811 recipient, _ = generate_user() 

812 existing_dm_recipient_id = recipient.id 

813 c.SendDirectMessage( 

814 conversations_pb2.SendDirectMessageReq(recipient_user_id=existing_dm_recipient_id, text="hi") 

815 ) 

816 

817 email = email_collector.pop_for_reports(last=True) 

818 assert email.plain.startswith( 

819 f"User {user.username} has sent {rate_limit_definition.warning_limit} chat initiations in the past {RATE_LIMIT_HOURS} hours." 

820 ) 

821 

822 for _ in range(rate_limit_definition.hard_limit - rate_limit_definition.warning_limit - 1): 

823 recipient, _ = generate_user() 

824 c.SendDirectMessage(conversations_pb2.SendDirectMessageReq(recipient_user_id=recipient.id, text="hi")) 

825 

826 assert email_collector.count_for_reports() == 0 

827 

828 # follow-up into an existing DM must not count as a new initiation 

829 c.SendDirectMessage( 

830 conversations_pb2.SendDirectMessageReq(recipient_user_id=existing_dm_recipient_id, text="follow-up") 

831 ) 

832 assert email_collector.count_for_reports() == 0 

833 

834 recipient, _ = generate_user() 

835 with pytest.raises(grpc.RpcError) as exc_info: 

836 c.SendDirectMessage(conversations_pb2.SendDirectMessageReq(recipient_user_id=recipient.id, text="hi")) 

837 assert exc_info.value.code() == grpc.StatusCode.RESOURCE_EXHAUSTED 

838 assert ( 

839 exc_info.value.details() 

840 == "You have messaged a lot of users in the past 24 hours. To avoid spam, you can't contact any more users for now." 

841 ) 

842 

843 email = email_collector.pop_for_reports(last=True) 

844 assert email.plain.startswith( 

845 f"User {user.username} has sent {rate_limit_definition.hard_limit} chat initiations in the past {RATE_LIMIT_HOURS} hours." 

846 ) 

847 assert "The user has been blocked from sending further chat initiations for now." in email.plain 

848 

849 

850def test_leave_invite_to_group_chat(db, moderator): 

851 user1, token1 = generate_user() 

852 user2, token2 = generate_user() 

853 user3, token3 = generate_user() 

854 user4, token4 = generate_user() 

855 user5, token5 = generate_user() 

856 user6, token6 = generate_user(delete_user=True) 

857 user7, token7 = generate_user() 

858 user8, token8 = generate_user() 

859 

860 make_friends(user1, user2) 

861 make_friends(user1, user3) 

862 make_friends(user1, user5) 

863 make_friends(user1, user7) 

864 make_friends(user1, user8) 

865 make_friends(user2, user3) 

866 make_friends(user4, user3) 

867 make_user_block(user1, user7) 

868 make_user_block(user8, user1) 

869 

870 with conversations_session(token1) as c: 

871 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user5.id])) 

872 group_chat_id = res.group_chat_id 

873 moderator.approve_group_chat(group_chat_id) 

874 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1")) 

875 

876 # other user not in chat 

877 with conversations_session(token3) as c: 

878 with pytest.raises(grpc.RpcError) as e: 

879 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id)) 

880 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

881 with pytest.raises(grpc.RpcError) as e: 

882 res = c.InviteToGroupChat( 

883 conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user4.id) 

884 ) 

885 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

886 with pytest.raises(grpc.RpcError) as e: 

887 res = c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id)) 

888 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

889 

890 with conversations_session(token2) as c: 

891 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id)) 

892 assert user3.id not in res.member_user_ids 

893 

894 # only_admins_invite defaults to true so shouldn't be able to invite 

895 with pytest.raises(grpc.RpcError) as e: 

896 res = c.InviteToGroupChat( 

897 conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id) 

898 ) 

899 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED 

900 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id)) 

901 

902 with conversations_session(token1) as c: 

903 # invite invisible user fails 

904 with pytest.raises(grpc.RpcError) as e: 

905 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user6.id)) 

906 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

907 assert e.value.details() == "Couldn't find that user." 

908 # invite fake user fails 

909 with pytest.raises(grpc.RpcError) as e: 

910 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=999)) 

911 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

912 assert e.value.details() == "Couldn't find that user." 

913 # invite blocked user fails 

914 with pytest.raises(grpc.RpcError) as e: 

915 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user7.id)) 

916 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

917 assert e.value.details() == "Couldn't find that user." 

918 # invite blocking user fails 

919 with pytest.raises(grpc.RpcError) as e: 

920 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user8.id)) 

921 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

922 assert e.value.details() == "Couldn't find that user." 

923 

924 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id)) 

925 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id)) 

926 assert user1.id in res.member_user_ids 

927 assert user5.id in res.member_user_ids 

928 assert user3.id in res.member_user_ids 

929 

930 # test non-admin inviting 

931 c.EditGroupChat( 

932 conversations_pb2.EditGroupChatReq( 

933 group_chat_id=group_chat_id, only_admins_invite=wrappers_pb2.BoolValue(value=False) 

934 ) 

935 ) 

936 

937 with conversations_session(token3) as c: 

938 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user2.id)) 

939 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id)) 

940 assert user2.id in res.member_user_ids 

941 

942 

943def test_group_chats_with_messages_before_join(db, moderator): 

944 """ 

945 If user 1 and 2 have a group chat and send messages, then add user 3; user 3 

946 should still see the group chat! 

947 """ 

948 user1, token1 = generate_user() 

949 user2, token2 = generate_user() 

950 user3, token3 = generate_user() 

951 user4, token4 = generate_user() 

952 

953 make_friends(user1, user2) 

954 make_friends(user1, user3) 

955 make_friends(user2, user3) 

956 make_friends(user1, user4) 

957 

958 with conversations_session(token1) as c: 

959 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user4.id])) 

960 group_chat_id = res.group_chat_id 

961 moderator.approve_group_chat(group_chat_id) 

962 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1")) 

963 

964 with conversations_session(token2) as c: 

965 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 2")) 

966 

967 with conversations_session(token1) as c: 

968 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 3")) 

969 

970 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id)) 

971 

972 with conversations_session(token3) as c: 

973 # should work 

974 c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=group_chat_id)) 

975 

976 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq()) 

977 assert len(res.group_chats) == 1 

978 

979 

980def test_invite_to_dm(db): 

981 user1, token1 = generate_user() 

982 user2, token2 = generate_user() 

983 user3, token3 = generate_user() 

984 

985 make_friends(user1, user2) 

986 make_friends(user1, user3) 

987 make_friends(user2, user3) 

988 

989 with conversations_session(token1) as c: 

990 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])) 

991 group_chat_id = res.group_chat_id 

992 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1")) 

993 

994 # dm, shou;dn't be able to invite someone else 

995 with pytest.raises(grpc.RpcError) as e: 

996 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id)) 

997 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION 

998 assert e.value.details() == "You can't invite other users to a direct message." 

999 

1000 

1001def test_sole_admin_leaves(db, moderator): 

1002 user1, token1 = generate_user() 

1003 user2, token2 = generate_user() 

1004 user3, token3 = generate_user() 

1005 

1006 make_friends(user1, user2) 

1007 make_friends(user1, user3) 

1008 make_friends(user2, user3) 

1009 

1010 with conversations_session(token1) as c: 

1011 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])) 

1012 group_chat_id = res.group_chat_id 

1013 moderator.approve_group_chat(group_chat_id) 

1014 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1")) 

1015 

1016 # sole admin can't leave group chat 

1017 with pytest.raises(grpc.RpcError) as e: 

1018 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id)) 

1019 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION 

1020 assert e.value.details() == "The last admin can't leave a group chat." 

1021 

1022 with conversations_session(token2) as c: 

1023 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id)) 

1024 

1025 with conversations_session(token3) as c: 

1026 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id)) 

1027 

1028 # sole admin can leave when last in chat 

1029 with conversations_session(token1) as c: 

1030 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id)) 

1031 

1032 

1033def test_search_messages(db, moderator): 

1034 user1, token1 = generate_user() 

1035 user2, token2 = generate_user() 

1036 user3, token3 = generate_user() 

1037 

1038 make_friends(user1, user2) 

1039 make_friends(user1, user3) 

1040 

1041 with conversations_session(token1) as c: 

1042 # create some threads with messages 

1043 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])) 

1044 gc1_id = res.group_chat_id 

1045 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gc1_id, text="Test message 1")) 

1046 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gc1_id, text="Test message 2")) 

1047 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])) 

1048 gc2_id = res.group_chat_id 

1049 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gc2_id, text="Test group message 3")) 

1050 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gc2_id, text="Test group message 4")) 

1051 

1052 # Approve group chats so they appear in search results 

1053 moderator.approve_group_chat(gc1_id) 

1054 moderator.approve_group_chat(gc2_id) 

1055 

1056 with conversations_session(token1) as c: 

1057 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="message ")) 

1058 assert len(res.results) == 4 

1059 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="group ")) 

1060 assert len(res.results) == 2 

1061 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="message 5")) 

1062 assert len(res.results) == 0 

1063 

1064 # outside user doesn't get results 

1065 with conversations_session(token3) as c: 

1066 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="Test message")) 

1067 assert len(res.results) == 0 

1068 

1069 

1070def test_search_messages_left_joined(db, moderator): 

1071 user1, token1 = generate_user() 

1072 user2, token2 = generate_user() 

1073 user3, token3 = generate_user() 

1074 user4, token4 = generate_user() 

1075 make_friends(user1, user2) 

1076 make_friends(user1, user3) 

1077 make_friends(user1, user4) 

1078 

1079 with conversations_session(token1) as c: 

1080 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user4.id])) 

1081 group_chat_id = res.group_chat_id 

1082 moderator.approve_group_chat(group_chat_id) 

1083 for i in range(10): 

1084 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message " + str(i))) 

1085 

1086 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id)) 

1087 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 10")) 

1088 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="Test message")) 

1089 

1090 assert len(res.results) == 11 

1091 

1092 with conversations_session(token3) as c: 

1093 # can only see last message after invited 

1094 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="Test message")) 

1095 

1096 assert len(res.results) == 1 

1097 assert res.results[0].message.text.text == "Test message 10" 

1098 

1099 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id)) 

1100 

1101 with conversations_session(token1) as c: 

1102 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 11")) 

1103 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 12")) 

1104 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user3.id)) 

1105 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 13")) 

1106 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 14")) 

1107 

1108 with conversations_session(token3) as c: 

1109 # can only see last message after invited 

1110 res = c.SearchMessages(conversations_pb2.SearchMessagesReq(query="Test message")) 

1111 assert len(res.results) == 3 

1112 assert res.results[0].message.text.text == "Test message 14" 

1113 assert res.results[1].message.text.text == "Test message 13" 

1114 assert res.results[2].message.text.text == "Test message 10" 

1115 

1116 

1117def test_admin_behaviour(db, moderator): 

1118 user1, token1 = generate_user() 

1119 user2, token2 = generate_user() 

1120 user3, token3 = generate_user() 

1121 

1122 make_friends(user1, user2) 

1123 make_friends(user1, user3) 

1124 make_friends(user2, user3) 

1125 

1126 with conversations_session(token1) as c: 

1127 gcid = c.CreateGroupChat( 

1128 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]) 

1129 ).group_chat_id 

1130 moderator.approve_group_chat(gcid) 

1131 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user2.id)) 

1132 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1133 assert len(res.admin_user_ids) == 2 

1134 assert user1.id in res.admin_user_ids 

1135 assert user2.id in res.admin_user_ids 

1136 

1137 with conversations_session(token3) as c: 

1138 with pytest.raises(grpc.RpcError) as e: 

1139 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id)) 

1140 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED 

1141 with pytest.raises(grpc.RpcError) as e: 

1142 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user1.id)) 

1143 assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED 

1144 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1145 assert len(res.admin_user_ids) == 2 

1146 assert user1.id in res.admin_user_ids 

1147 assert user2.id in res.admin_user_ids 

1148 

1149 with conversations_session(token2) as c: 

1150 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id)) 

1151 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1152 assert len(res.admin_user_ids) == 3 

1153 assert user1.id in res.admin_user_ids 

1154 assert user2.id in res.admin_user_ids 

1155 assert user3.id in res.admin_user_ids 

1156 

1157 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user1.id)) 

1158 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1159 assert len(res.admin_user_ids) == 2 

1160 assert user2.id in res.admin_user_ids 

1161 assert user3.id in res.admin_user_ids 

1162 

1163 with conversations_session(token1) as c: 

1164 with pytest.raises(grpc.RpcError): 

1165 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user1.id)) 

1166 with pytest.raises(grpc.RpcError): 

1167 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id)) 

1168 with pytest.raises(grpc.RpcError): 

1169 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user2.id)) 

1170 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1171 assert len(res.admin_user_ids) == 2 

1172 assert user2.id in res.admin_user_ids 

1173 assert user3.id in res.admin_user_ids 

1174 

1175 with conversations_session(token2) as c: 

1176 # can demote self if there are other admins 

1177 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user2.id)) 

1178 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1179 assert len(res.admin_user_ids) == 1 

1180 assert user3.id in res.admin_user_ids 

1181 

1182 with conversations_session(token3) as c: 

1183 with pytest.raises(grpc.RpcError) as e: 

1184 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id)) 

1185 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION 

1186 assert e.value.details() == "You can't remove the last admin." 

1187 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1188 assert len(res.admin_user_ids) == 1 

1189 assert user3.id in res.admin_user_ids 

1190 

1191 # last admin can't leave 

1192 with pytest.raises(grpc.RpcError) as e: 

1193 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid)) 

1194 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION 

1195 assert e.value.details() == "The last admin can't leave a group chat." 

1196 

1197 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user1.id)) 

1198 

1199 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid)) 

1200 

1201 with conversations_session(token2) as c: 

1202 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid)) 

1203 

1204 # last participant must be admin but can leave to orphan chat 

1205 with conversations_session(token1) as c: 

1206 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid)) 

1207 

1208 

1209def test_add_remove_admin_failures(db): 

1210 user1, token1 = generate_user() 

1211 user2, token2 = generate_user() 

1212 user3, token3 = generate_user() 

1213 user4, token4 = generate_user() 

1214 user5, token5 = generate_user() 

1215 

1216 make_friends(user1, user2) 

1217 make_friends(user1, user3) 

1218 make_friends(user1, user4) 

1219 make_friends(user1, user5) 

1220 

1221 with conversations_session(token1) as c: 

1222 gcid = c.CreateGroupChat( 

1223 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id, user4.id, user5.id]) 

1224 ).group_chat_id 

1225 

1226 make_user_invisible(user3.id) 

1227 make_user_block(user1, user4) 

1228 make_user_block(user5, user1) 

1229 

1230 # make non-existent user admin 

1231 with pytest.raises(grpc.RpcError) as e: 

1232 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=999)) 

1233 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

1234 assert e.value.details() == "Couldn't find that user." 

1235 

1236 # make invisible user admin 

1237 with pytest.raises(grpc.RpcError) as e: 

1238 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id)) 

1239 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

1240 assert e.value.details() == "Couldn't find that user." 

1241 

1242 # make blocked user admin 

1243 with pytest.raises(grpc.RpcError) as e: 

1244 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user4.id)) 

1245 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

1246 assert e.value.details() == "Couldn't find that user." 

1247 

1248 # make blocking user admin 

1249 with pytest.raises(grpc.RpcError) as e: 

1250 c.MakeGroupChatAdmin(conversations_pb2.MakeGroupChatAdminReq(group_chat_id=gcid, user_id=user5.id)) 

1251 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

1252 assert e.value.details() == "Couldn't find that user." 

1253 

1254 with session_scope() as session: 

1255 subscriptions = ( 

1256 session.execute( 

1257 select(GroupChatSubscription) 

1258 .where(GroupChatSubscription.group_chat_id == gcid) 

1259 .where(GroupChatSubscription.role == GroupChatRole.participant) 

1260 ) 

1261 .scalars() 

1262 .all() 

1263 ) 

1264 

1265 for subscription in subscriptions: 

1266 subscription.role = GroupChatRole.admin 

1267 

1268 with conversations_session(token1) as c: 

1269 # remove non-existent user admin 

1270 with pytest.raises(grpc.RpcError) as e: 

1271 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=999)) 

1272 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

1273 assert e.value.details() == "Couldn't find that user." 

1274 

1275 # remove invisible admin 

1276 with pytest.raises(grpc.RpcError) as e: 

1277 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user3.id)) 

1278 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

1279 assert e.value.details() == "Couldn't find that user." 

1280 

1281 # remove blocked admin 

1282 with pytest.raises(grpc.RpcError) as e: 

1283 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user4.id)) 

1284 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

1285 assert e.value.details() == "Couldn't find that user." 

1286 

1287 # remove blocking admin 

1288 with pytest.raises(grpc.RpcError) as e: 

1289 c.RemoveGroupChatAdmin(conversations_pb2.RemoveGroupChatAdminReq(group_chat_id=gcid, user_id=user5.id)) 

1290 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

1291 assert e.value.details() == "Couldn't find that user." 

1292 

1293 

1294def test_last_seen(db, moderator): 

1295 user1, token1 = generate_user() 

1296 user2, token2 = generate_user() 

1297 user3, token3 = generate_user() 

1298 

1299 make_friends(user1, user2) 

1300 make_friends(user1, user3) 

1301 make_friends(user2, user3) 

1302 

1303 with conversations_session(token3) as c: 

1304 # this is just here to mess up any issues we get if we pretend there's only one group chat ever 

1305 gcid_distraction = c.CreateGroupChat( 

1306 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user1.id]) 

1307 ).group_chat_id 

1308 moderator.approve_group_chat(gcid_distraction) 

1309 

1310 with conversations_session(token1) as c: 

1311 gcid = c.CreateGroupChat( 

1312 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]) 

1313 ).group_chat_id 

1314 moderator.approve_group_chat(gcid) 

1315 

1316 message_ids = [] 

1317 

1318 for i in range(6): 

1319 c.SendMessage( 

1320 conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text=f"gibberish message... {i}") 

1321 ) 

1322 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text=f"test message {i}")) 

1323 c.SendMessage( 

1324 conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text=f"gibberish message {i}") 

1325 ) 

1326 

1327 message_ids.append( 

1328 c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)).latest_message.message_id 

1329 ) 

1330 

1331 # messages are automatically marked as seen when you send a new message 

1332 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1333 assert res.unseen_message_count == 0 

1334 

1335 with conversations_session(token2) as c: 

1336 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1337 # created + 6 normal 

1338 assert res.unseen_message_count == 7 

1339 

1340 backward_offset = 3 

1341 c.MarkLastSeenGroupChat( 

1342 conversations_pb2.MarkLastSeenGroupChatReq( 

1343 group_chat_id=gcid, last_seen_message_id=message_ids[-backward_offset - 1] 

1344 ) 

1345 ) 

1346 

1347 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1348 assert res.unseen_message_count == backward_offset 

1349 

1350 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="test message ...")) 

1351 

1352 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1353 assert res.unseen_message_count == 0 

1354 

1355 with conversations_session(token3) as c: 

1356 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1357 # created + 7 normal 

1358 assert res.unseen_message_count == 8 

1359 

1360 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="test message ...")) 

1361 

1362 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1363 assert res.unseen_message_count == 0 

1364 

1365 

1366def test_mark_last_seen_clears_notifications(db, moderator): 

1367 user1, token1 = generate_user() 

1368 user2, token2 = generate_user() 

1369 

1370 with conversations_session(token1) as c: 

1371 gcid = c.CreateGroupChat( 

1372 conversations_pb2.CreateGroupChatReq( 

1373 recipient_user_ids=[user2.id], title=wrappers_pb2.StringValue(value="Test chat") 

1374 ) 

1375 ).group_chat_id 

1376 

1377 moderator.approve_group_chat(gcid) 

1378 

1379 with conversations_session(token1) as c: 

1380 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello")) 

1381 

1382 process_jobs() 

1383 

1384 def unseen_notification_count(user_id): 

1385 with session_scope() as session: 

1386 return session.execute( 

1387 select(func.count()) 

1388 .select_from(Notification) 

1389 .where(Notification.user_id == user_id) 

1390 .where(Notification.key == str(gcid)) 

1391 .where(Notification.is_seen == False) 

1392 ).scalar_one() 

1393 

1394 assert unseen_notification_count(user2.id) > 0 

1395 

1396 with conversations_session(token2) as c: 

1397 c.MarkLastSeenGroupChat(conversations_pb2.MarkLastSeenGroupChatReq(group_chat_id=gcid, last_seen_message_id=1)) 

1398 

1399 assert unseen_notification_count(user2.id) == 0 

1400 

1401 

1402def test_one_dm_per_pair(db, moderator): 

1403 user1, token1 = generate_user() 

1404 user2, token2 = generate_user() 

1405 user3, token3 = generate_user() 

1406 

1407 make_friends(user1, user2) 

1408 make_friends(user1, user3) 

1409 make_friends(user2, user3) 

1410 

1411 with conversations_session(token1) as c: 

1412 # create DM with user 2 

1413 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])) 

1414 assert res.is_dm 

1415 dm_with_user2 = res.group_chat_id 

1416 

1417 # create DM with user 3 

1418 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id])) 

1419 assert res.is_dm 

1420 dm_with_user3 = res.group_chat_id 

1421 

1422 # can't create another group chat with just user 2 

1423 with pytest.raises(grpc.RpcError) as e: 

1424 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])) 

1425 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION 

1426 

1427 # can't create another group chat with just user 3 

1428 with pytest.raises(grpc.RpcError) as e: 

1429 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id])) 

1430 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION 

1431 

1432 # can create joined group chat 

1433 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])) 

1434 assert not res.is_dm 

1435 

1436 # Approve the DMs so user2 can see them (otherwise they're SHADOWED and only visible to creator) 

1437 moderator.approve_group_chat(dm_with_user2) 

1438 

1439 with conversations_session(token2) as c: 

1440 # can create DM with user 3 

1441 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id])) 

1442 assert res.is_dm 

1443 

1444 # can't create another group chat with just user 1 (DM was approved, so user2 can see it) 

1445 with pytest.raises(grpc.RpcError) as e: 

1446 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user1.id])) 

1447 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION 

1448 

1449 

1450def test_GetDirectMessage(db): 

1451 user1, token1 = generate_user() 

1452 user2, token2 = generate_user() 

1453 user3, token3 = generate_user() 

1454 

1455 make_friends(user1, user2) 

1456 make_friends(user1, user3) 

1457 make_friends(user2, user3) 

1458 

1459 with conversations_session(token1) as c: 

1460 # no group chat with user 2 

1461 with pytest.raises(grpc.RpcError) as e: 

1462 res = c.GetDirectMessage(conversations_pb2.GetDirectMessageReq(user_id=user2.id)) 

1463 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

1464 

1465 # no group chat with nor user 3 

1466 with pytest.raises(grpc.RpcError) as e: 

1467 res = c.GetDirectMessage(conversations_pb2.GetDirectMessageReq(user_id=user3.id)) 

1468 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

1469 

1470 # create DM with user 2 

1471 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])) 

1472 assert res.is_dm 

1473 gcid = res.group_chat_id 

1474 

1475 # now should exist 

1476 res = c.GetDirectMessage(conversations_pb2.GetDirectMessageReq(user_id=user2.id)) 

1477 assert res.group_chat_id == gcid 

1478 assert not res.is_archived 

1479 

1480 # create DM with user 3 

1481 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id])) 

1482 assert res.is_dm 

1483 

1484 # can create joined group chat 

1485 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id])) 

1486 assert not res.is_dm 

1487 

1488 with conversations_session(token2) as c: 

1489 # can create DM with user 3 

1490 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id])) 

1491 assert res.is_dm 

1492 assert res.can_message 

1493 gcid = res.group_chat_id 

1494 

1495 # DM with 3 should exist, but can't message after being blocked 

1496 make_user_block(user3, user2) 

1497 res = c.GetDirectMessage(conversations_pb2.GetDirectMessageReq(user_id=user3.id)) 

1498 assert res.group_chat_id == gcid 

1499 assert not res.can_message 

1500 

1501 

1502def test_total_unseen(db, moderator): 

1503 user1, token1 = generate_user() 

1504 user2, token2 = generate_user() 

1505 user3, token3 = generate_user() 

1506 

1507 # distractions 

1508 user4, token4 = generate_user() 

1509 

1510 make_friends(user1, user2) 

1511 make_friends(user1, user3) 

1512 make_friends(user2, user3) 

1513 

1514 # distractions 

1515 make_friends(user1, user4) 

1516 

1517 with conversations_session(token1) as c: 

1518 # distractions 

1519 gcid_distraction = c.CreateGroupChat( 

1520 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user4.id]) 

1521 ).group_chat_id 

1522 moderator.approve_group_chat(gcid_distraction) 

1523 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction...")) 

1524 

1525 gcid = c.CreateGroupChat( 

1526 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]) 

1527 ).group_chat_id 

1528 moderator.approve_group_chat(gcid) 

1529 

1530 for i in range(6): 

1531 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text=f"test message {i}")) 

1532 

1533 # distractions 

1534 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction...")) 

1535 

1536 # messages are automatically marked as seen when you send a new message 

1537 with api_session(token1) as api: 

1538 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 0 

1539 

1540 with api_session(token2) as api: 

1541 # chat created + 6 normal messages 

1542 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 7 

1543 

1544 # now leave chat with user2 

1545 with conversations_session(token2) as c: 

1546 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid)) 

1547 

1548 with api_session(token2) as api: 

1549 # seen messages becomes 0 when leaving 

1550 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 0 

1551 

1552 with conversations_session(token1) as c: 

1553 # distractions 

1554 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction...")) 

1555 

1556 # send more stuff without user 2 

1557 for i in range(3): 

1558 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text=f"test message {i}")) 

1559 

1560 # distractions 

1561 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction...")) 

1562 

1563 with api_session(token2) as api: 

1564 # seen messages becomes 0 when leaving 

1565 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 0 

1566 

1567 with conversations_session(token1) as c: 

1568 # add user 2 back 

1569 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=gcid, user_id=user2.id)) 

1570 

1571 # send more stuff with user 2 

1572 for i in range(12): 

1573 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text=f"test message {i}")) 

1574 

1575 # distractions 

1576 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid_distraction, text="distraction...")) 

1577 

1578 with api_session(token2) as api: 

1579 # joined + 12 normal 

1580 assert api.Ping(api_pb2.PingReq()).unseen_message_count == 13 

1581 

1582 

1583def test_regression_ListGroupChats_pagination(db, moderator): 

1584 user1, token1 = generate_user() 

1585 user2, token2 = generate_user() 

1586 user3, token3 = generate_user() 

1587 

1588 make_friends(user1, user2) 

1589 make_friends(user1, user3) 

1590 

1591 with conversations_session(token1) as c: 

1592 # tuples of (group_chat_id, message_id) 

1593 group_chat_and_message_ids = [] 

1594 for i in range(50): 

1595 res1 = c.CreateGroupChat( 

1596 conversations_pb2.CreateGroupChatReq( 

1597 recipient_user_ids=[user2.id, user3.id], title=wrappers_pb2.StringValue(value=f"Chat {i}") 

1598 ) 

1599 ) 

1600 

1601 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=res1.group_chat_id, text=f"Test message {i}")) 

1602 

1603 res2 = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=res1.group_chat_id)) 

1604 

1605 group_chat_and_message_ids.append((res2.group_chat_id, res2.latest_message.message_id)) 

1606 moderator.approve_group_chat(res1.group_chat_id) 

1607 

1608 seen_group_chat_ids = [] 

1609 

1610 last_message_id = 0 

1611 more = True 

1612 while more: 

1613 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(last_message_id=last_message_id)) 

1614 last_message_id = res.last_message_id 

1615 more = not res.no_more 

1616 

1617 seen_group_chat_ids.extend([chat.group_chat_id for chat in res.group_chats]) 

1618 

1619 assert set(seen_group_chat_ids) == {x[0] for x in group_chat_and_message_ids}, "Not all group chats returned" 

1620 

1621 

1622def test_muting(db, moderator): 

1623 user1, token1 = generate_user() 

1624 user2, token2 = generate_user() 

1625 user3, token3 = generate_user() 

1626 

1627 make_friends(user1, user2) 

1628 make_friends(user1, user3) 

1629 make_friends(user2, user3) 

1630 

1631 with conversations_session(token3) as c: 

1632 # this is just here to mess up any issues we get if we pretend there's only one group chat ever 

1633 gcid_distraction = c.CreateGroupChat( 

1634 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user1.id]) 

1635 ).group_chat_id 

1636 moderator.approve_group_chat(gcid_distraction) 

1637 

1638 with conversations_session(token1) as c: 

1639 gcid = c.CreateGroupChat( 

1640 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]) 

1641 ).group_chat_id 

1642 moderator.approve_group_chat(gcid) 

1643 

1644 with conversations_session(token2) as c: 

1645 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1646 assert not res.mute_info.muted 

1647 assert not res.mute_info.HasField("muted_until") 

1648 

1649 c.MuteGroupChat(conversations_pb2.MuteGroupChatReq(group_chat_id=gcid, forever=True)) 

1650 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1651 assert res.mute_info.muted 

1652 assert not res.mute_info.HasField("muted_until") 

1653 

1654 c.MuteGroupChat(conversations_pb2.MuteGroupChatReq(group_chat_id=gcid, unmute=True)) 

1655 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1656 assert not res.mute_info.muted 

1657 assert not res.mute_info.HasField("muted_until") 

1658 

1659 c.MuteGroupChat( 

1660 conversations_pb2.MuteGroupChatReq( 

1661 group_chat_id=gcid, for_duration=Duration_from_timedelta(timedelta(hours=2)) 

1662 ) 

1663 ) 

1664 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1665 assert res.mute_info.muted 

1666 assert res.mute_info.HasField("muted_until") 

1667 assert to_aware_datetime(res.mute_info.muted_until) >= now() + timedelta(hours=1, minutes=59) 

1668 assert to_aware_datetime(res.mute_info.muted_until) <= now() + timedelta(hours=2, minutes=1) 

1669 

1670 

1671def test_archiving(db, moderator): 

1672 """Test SetGroupChatArchiveStatus RPC with GetGroupChat and ListGroupChats""" 

1673 user1, token1 = generate_user() 

1674 user2, token2 = generate_user() 

1675 user3, token3 = generate_user() 

1676 

1677 make_friends(user1, user2) 

1678 make_friends(user1, user3) 

1679 make_friends(user2, user3) 

1680 

1681 # Create a distraction chat to ensure we're testing the right one 

1682 with conversations_session(token3) as c: 

1683 gcid_distraction = c.CreateGroupChat( 

1684 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user1.id]) 

1685 ).group_chat_id 

1686 moderator.approve_group_chat(gcid_distraction) 

1687 

1688 with conversations_session(token1) as c: 

1689 gcid = c.CreateGroupChat( 

1690 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]) 

1691 ).group_chat_id 

1692 moderator.approve_group_chat(gcid) 

1693 

1694 # Test basic archive/unarchive functionality 

1695 with conversations_session(token2) as c: 

1696 # Initially not archived 

1697 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1698 assert not res.is_archived 

1699 

1700 # Archive the chat 

1701 archive_res = c.SetGroupChatArchiveStatus( 

1702 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True) 

1703 ) 

1704 assert archive_res.group_chat_id == gcid 

1705 assert archive_res.is_archived 

1706 

1707 # Verify archived via GetGroupChat 

1708 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1709 assert res.is_archived 

1710 

1711 # Unarchive the chat 

1712 archive_res = c.SetGroupChatArchiveStatus( 

1713 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False) 

1714 ) 

1715 assert archive_res.group_chat_id == gcid 

1716 assert not archive_res.is_archived 

1717 

1718 # Verify unarchived via GetGroupChat 

1719 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1720 assert not res.is_archived 

1721 

1722 

1723def test_archiving_per_user(db, moderator): 

1724 """Test that archiving is per-user - one user archiving doesn't affect others""" 

1725 user1, token1 = generate_user() 

1726 user2, token2 = generate_user() 

1727 

1728 make_friends(user1, user2) 

1729 

1730 with conversations_session(token1) as c: 

1731 gcid = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id 

1732 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello")) 

1733 moderator.approve_group_chat(gcid) 

1734 

1735 # User1 archives the chat 

1736 with conversations_session(token1) as c: 

1737 c.SetGroupChatArchiveStatus( 

1738 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True) 

1739 ) 

1740 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1741 assert res.is_archived 

1742 

1743 # User2 should NOT see it as archived 

1744 with conversations_session(token2) as c: 

1745 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1746 assert not res.is_archived 

1747 

1748 # User2 archives it too 

1749 with conversations_session(token2) as c: 

1750 c.SetGroupChatArchiveStatus( 

1751 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True) 

1752 ) 

1753 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1754 assert res.is_archived 

1755 

1756 # User1 unarchives - user2 should still see it as archived 

1757 with conversations_session(token1) as c: 

1758 c.SetGroupChatArchiveStatus( 

1759 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False) 

1760 ) 

1761 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1762 assert not res.is_archived 

1763 

1764 with conversations_session(token2) as c: 

1765 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1766 assert res.is_archived 

1767 

1768 

1769def test_archiving_with_list_group_chats(db, moderator): 

1770 """Test archive filtering with ListGroupChats endpoint""" 

1771 user1, token1 = generate_user() 

1772 user2, token2 = generate_user() 

1773 user3, token3 = generate_user() 

1774 

1775 make_friends(user1, user2) 

1776 make_friends(user1, user3) 

1777 

1778 with conversations_session(token1) as c: 

1779 # Create 3 chats 

1780 gcid1 = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id 

1781 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid1, text="Chat 1")) 

1782 moderator.approve_group_chat(gcid1) 

1783 

1784 gcid2 = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id])).group_chat_id 

1785 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid2, text="Chat 2")) 

1786 moderator.approve_group_chat(gcid2) 

1787 

1788 gcid3 = c.CreateGroupChat( 

1789 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]) 

1790 ).group_chat_id 

1791 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid3, text="Chat 3")) 

1792 moderator.approve_group_chat(gcid3) 

1793 

1794 with conversations_session(token1) as c: 

1795 # Initially all 3 chats should be visible 

1796 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq()) 

1797 assert len(res.group_chats) == 3 

1798 

1799 # All should be non-archived 

1800 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False)) 

1801 assert len(res.group_chats) == 3 

1802 

1803 # None should be archived 

1804 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True)) 

1805 assert len(res.group_chats) == 0 

1806 

1807 # Archive chat 1 

1808 c.SetGroupChatArchiveStatus( 

1809 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid1, is_archived=True) 

1810 ) 

1811 

1812 # Without filter, still see all 3 

1813 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq()) 

1814 assert len(res.group_chats) == 3 

1815 

1816 # Non-archived should show 2 

1817 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False)) 

1818 assert len(res.group_chats) == 2 

1819 assert gcid1 not in [gc.group_chat_id for gc in res.group_chats] 

1820 

1821 # Archived should show 1 

1822 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True)) 

1823 assert len(res.group_chats) == 1 

1824 assert res.group_chats[0].group_chat_id == gcid1 

1825 assert res.group_chats[0].is_archived 

1826 

1827 # Archive chat 2 as well 

1828 c.SetGroupChatArchiveStatus( 

1829 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid2, is_archived=True) 

1830 ) 

1831 

1832 # Non-archived should show 1 

1833 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False)) 

1834 assert len(res.group_chats) == 1 

1835 assert res.group_chats[0].group_chat_id == gcid3 

1836 

1837 # Archived should show 2 

1838 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True)) 

1839 assert len(res.group_chats) == 2 

1840 archived_ids = {gc.group_chat_id for gc in res.group_chats} 

1841 assert archived_ids == {gcid1, gcid2} 

1842 

1843 # Unarchive chat 1 

1844 c.SetGroupChatArchiveStatus( 

1845 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid1, is_archived=False) 

1846 ) 

1847 

1848 # Non-archived should show 2 

1849 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=False)) 

1850 assert len(res.group_chats) == 2 

1851 

1852 # Archived should show 1 

1853 res = c.ListGroupChats(conversations_pb2.ListGroupChatsReq(only_archived=True)) 

1854 assert len(res.group_chats) == 1 

1855 assert res.group_chats[0].group_chat_id == gcid2 

1856 

1857 

1858def test_archiving_chat_not_found(db, moderator): 

1859 """Test that archiving a non-existent or non-accessible chat fails""" 

1860 user1, token1 = generate_user() 

1861 user2, token2 = generate_user() 

1862 user3, token3 = generate_user() 

1863 

1864 make_friends(user1, user2) 

1865 

1866 with conversations_session(token1) as c: 

1867 gcid = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id 

1868 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello")) 

1869 moderator.approve_group_chat(gcid) 

1870 

1871 # User3 is not in the chat - should get NOT_FOUND 

1872 with conversations_session(token3) as c: 

1873 with pytest.raises(grpc.RpcError) as e: 

1874 c.SetGroupChatArchiveStatus( 

1875 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True) 

1876 ) 

1877 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

1878 

1879 # Non-existent chat ID should fail 

1880 with conversations_session(token1) as c: 

1881 with pytest.raises(grpc.RpcError) as e: 

1882 c.SetGroupChatArchiveStatus( 

1883 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=99999, is_archived=True) 

1884 ) 

1885 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

1886 

1887 

1888def test_archiving_after_leaving_chat(db, moderator): 

1889 """Test that you can't archive a chat after leaving it""" 

1890 user1, token1 = generate_user() 

1891 user2, token2 = generate_user() 

1892 user3, token3 = generate_user() 

1893 

1894 make_friends(user1, user2) 

1895 make_friends(user1, user3) 

1896 make_friends(user2, user3) 

1897 

1898 with conversations_session(token1) as c: 

1899 gcid = c.CreateGroupChat( 

1900 conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id]) 

1901 ).group_chat_id 

1902 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello")) 

1903 moderator.approve_group_chat(gcid) 

1904 

1905 # User2 leaves the chat 

1906 with conversations_session(token2) as c: 

1907 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=gcid)) 

1908 

1909 # User2 should not be able to archive it now 

1910 with conversations_session(token2) as c: 

1911 with pytest.raises(grpc.RpcError) as e: 

1912 c.SetGroupChatArchiveStatus( 

1913 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True) 

1914 ) 

1915 assert e.value.code() == grpc.StatusCode.NOT_FOUND 

1916 

1917 

1918def test_archiving_dm(db, moderator): 

1919 """Test that archiving works for DMs as well as group chats""" 

1920 user1, token1 = generate_user() 

1921 user2, token2 = generate_user() 

1922 

1923 make_friends(user1, user2) 

1924 

1925 with conversations_session(token1) as c: 

1926 # Create a DM 

1927 gcid = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id 

1928 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello")) 

1929 moderator.approve_group_chat(gcid) 

1930 

1931 # Verify it's a DM 

1932 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1933 assert res.is_dm 

1934 assert not res.is_archived 

1935 

1936 # Archive the DM 

1937 c.SetGroupChatArchiveStatus( 

1938 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True) 

1939 ) 

1940 

1941 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1942 assert res.is_archived 

1943 

1944 # Unarchive it 

1945 c.SetGroupChatArchiveStatus( 

1946 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False) 

1947 ) 

1948 

1949 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1950 assert not res.is_archived 

1951 

1952 

1953def test_archiving_idempotent(db, moderator): 

1954 """Test that archiving/unarchiving is idempotent""" 

1955 user1, token1 = generate_user() 

1956 user2, token2 = generate_user() 

1957 

1958 make_friends(user1, user2) 

1959 

1960 with conversations_session(token1) as c: 

1961 gcid = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])).group_chat_id 

1962 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=gcid, text="Hello")) 

1963 moderator.approve_group_chat(gcid) 

1964 

1965 # Archive twice - should work without error 

1966 c.SetGroupChatArchiveStatus( 

1967 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True) 

1968 ) 

1969 c.SetGroupChatArchiveStatus( 

1970 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=True) 

1971 ) 

1972 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1973 assert res.is_archived 

1974 

1975 # Unarchive twice - should work without error 

1976 c.SetGroupChatArchiveStatus( 

1977 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False) 

1978 ) 

1979 c.SetGroupChatArchiveStatus( 

1980 conversations_pb2.SetGroupChatArchiveStatusReq(group_chat_id=gcid, is_archived=False) 

1981 ) 

1982 res = c.GetGroupChat(conversations_pb2.GetGroupChatReq(group_chat_id=gcid)) 

1983 assert not res.is_archived 

1984 

1985 

1986def test_chat_notifications(db, moderator): 

1987 user1, token1 = generate_user() 

1988 user2, token2 = generate_user() 

1989 # notifs off 

1990 user3, token3 = generate_user() 

1991 user4, token4 = generate_user() 

1992 user5, token5 = generate_user() 

1993 user6, token6 = generate_user() 

1994 

1995 make_friends(user1, user2) 

1996 make_friends(user1, user3) 

1997 make_friends(user1, user4) 

1998 make_friends(user4, user5) 

1999 make_friends(user4, user6) 

2000 

2001 # have some of them enable/disable notifs 

2002 topic_action = NotificationTopicAction.chat__message 

2003 for token, enabled in [ 

2004 (token1, True), 

2005 (token2, True), 

2006 (token3, False), 

2007 (token4, True), 

2008 (token5, True), 

2009 (token6, True), 

2010 ]: 

2011 with notifications_session(token) as notifications: 

2012 notifications.SetNotificationSettings( 

2013 notifications_pb2.SetNotificationSettingsReq( 

2014 preferences=[ 

2015 notifications_pb2.SingleNotificationPreference( 

2016 topic=topic_action.topic, 

2017 action=topic_action.action, 

2018 delivery_method=delivery_method, 

2019 enabled=enabled, 

2020 ) 

2021 for delivery_method in ["push", "email", "digest"] 

2022 ], 

2023 ) 

2024 ) 

2025 

2026 group_chat_id = None 

2027 

2028 def send_msg(c, i): 

2029 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text=f"Test message {i}")) 

2030 

2031 with conversations_session(token1) as c: 

2032 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id, user3.id, user4.id])) 

2033 group_chat_id = res.group_chat_id 

2034 moderator.approve_group_chat(group_chat_id) 

2035 c.EditGroupChat( 

2036 conversations_pb2.EditGroupChatReq( 

2037 group_chat_id=group_chat_id, only_admins_invite=wrappers_pb2.BoolValue(value=False) 

2038 ) 

2039 ) 

2040 send_msg(c, i=1) 

2041 send_msg(c, i=2) 

2042 

2043 with conversations_session(token4) as c: 

2044 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user5.id)) 

2045 send_msg(c, i=3) 

2046 c.InviteToGroupChat(conversations_pb2.InviteToGroupChatReq(group_chat_id=group_chat_id, user_id=user6.id)) 

2047 send_msg(c, i=4) 

2048 send_msg(c, i=5) 

2049 

2050 with conversations_session(token3) as c: 

2051 send_msg(c, i=6) 

2052 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id)) 

2053 

2054 with conversations_session(token2) as c: 

2055 send_msg(c, i=7) 

2056 c.LeaveGroupChat(conversations_pb2.LeaveGroupChatReq(group_chat_id=group_chat_id)) 

2057 

2058 with conversations_session(token6) as c: 

2059 send_msg(c, i=8) 

2060 

2061 # go through all bg jobs 

2062 while process_job(): 

2063 pass 

2064 

2065 # now check notifs... 

2066 expected_notifs = [ 

2067 (user1, "user1", [3, 4, 5, 6, 7, 8]), 

2068 (user2, "user2", [1, 2, 3, 4, 5, 6]), 

2069 (user3, "user3", []), # notifs off 

2070 (user4, "user4", [1, 2, 6, 7, 8]), 

2071 (user5, "user5", [3, 4, 5, 6, 7, 8]), 

2072 (user6, "user6", [4, 5, 6, 7]), 

2073 ] 

2074 

2075 with session_scope() as session: 

2076 for user, label, expected_msgs in expected_notifs: 

2077 deliv = ( 

2078 session.execute( 

2079 select(Notification.data) 

2080 .join(NotificationDelivery, NotificationDelivery.notification_id == Notification.id) 

2081 .where(Notification.user_id == user.id) 

2082 .where(Notification.topic_action == topic_action) 

2083 .where(NotificationDelivery.delivery_type == NotificationDeliveryType.push) 

2084 .order_by(Notification.created) 

2085 ) 

2086 .scalars() 

2087 .all() 

2088 ) 

2089 

2090 def parse_message_payload(data): 

2091 return notification_data_pb2.ChatMessage.FromString(data).text 

2092 

2093 contents = [parse_message_payload(d) for d in deliv] 

2094 

2095 print(contents) 

2096 

2097 assert [f"Test message {i}" for i in expected_msgs] == contents, f"Wrong messages for {label}" 

2098 

2099 

2100def test_incomplete_profile(db): 

2101 user1, token1 = generate_user(complete_profile=True) 

2102 user2, token2 = generate_user(complete_profile=False) 

2103 user3, token3 = generate_user(complete_profile=True) 

2104 make_friends(user1, user2) 

2105 make_friends(user1, user3) 

2106 

2107 # user 1 can make a chat 

2108 with conversations_session(token1) as c: 

2109 res = c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user2.id])) 

2110 group_chat_id = res.group_chat_id 

2111 c.SendMessage(conversations_pb2.SendMessageReq(group_chat_id=group_chat_id, text="Test message 1")) 

2112 res = c.GetGroupChatMessages(conversations_pb2.GetGroupChatMessagesReq(group_chat_id=group_chat_id)) 

2113 assert res.messages[0].text.text == "Test message 1" 

2114 assert to_aware_datetime(res.messages[0].time) <= now() 

2115 assert res.messages[0].author_user_id == user1.id 

2116 

2117 # user 2 cannot 

2118 with conversations_session(token2) as c: 

2119 with pytest.raises(grpc.RpcError) as e: 

2120 c.CreateGroupChat(conversations_pb2.CreateGroupChatReq(recipient_user_ids=[user3.id])) 

2121 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION 

2122 assert e.value.details() == "You have to complete your profile before you can send a message."