Coverage for src/tests/test_events.py: 100%

1165 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2025-03-11 15:27 +0000

1from datetime import timedelta 

2 

3import grpc 

4import pytest 

5from google.protobuf import wrappers_pb2 

6from psycopg2.extras import DateTimeTZRange 

7from sqlalchemy.sql.expression import update 

8 

9from couchers import errors 

10from couchers.db import session_scope 

11from couchers.models import EventOccurrence 

12from couchers.tasks import enforce_community_memberships 

13from couchers.utils import Timestamp_from_datetime, now, to_aware_datetime 

14from proto import admin_pb2, events_pb2, threads_pb2 

15from tests.test_communities import create_community, create_group 

16from tests.test_fixtures import ( # noqa 

17 db, 

18 email_fields, 

19 events_session, 

20 generate_user, 

21 mock_notification_email, 

22 process_jobs, 

23 push_collector, 

24 real_admin_session, 

25 testconfig, 

26 threads_session, 

27) 

28 

29 

30@pytest.fixture(autouse=True) 

31def _(testconfig): 

32 pass 

33 

34 

35def test_CreateEvent(db, push_collector): 

36 # test cases: 

37 # can create event 

38 # cannot create event with missing details 

39 # can create online event 

40 # can create in person event 

41 # can't create event that starts in the past 

42 # can create in different timezones 

43 

44 # event creator 

45 user1, token1 = generate_user() 

46 # community moderator 

47 user2, token2 = generate_user() 

48 # third party 

49 user3, token3 = generate_user() 

50 

51 with session_scope() as session: 

52 c_id = create_community(session, 0, 2, "Community", [user2], [], None).id 

53 

54 time_before = now() 

55 start_time = now() + timedelta(hours=2) 

56 end_time = start_time + timedelta(hours=3) 

57 

58 with events_session(token1) as api: 

59 # in person event 

60 res = api.CreateEvent( 

61 events_pb2.CreateEventReq( 

62 title="Dummy Title", 

63 content="Dummy content.", 

64 photo_key=None, 

65 offline_information=events_pb2.OfflineEventInformation( 

66 address="Near Null Island", 

67 lat=0.1, 

68 lng=0.2, 

69 ), 

70 start_time=Timestamp_from_datetime(start_time), 

71 end_time=Timestamp_from_datetime(end_time), 

72 timezone="UTC", 

73 ) 

74 ) 

75 

76 assert res.is_next 

77 assert res.title == "Dummy Title" 

78 assert res.slug == "dummy-title" 

79 assert res.content == "Dummy content." 

80 assert not res.photo_url 

81 assert res.WhichOneof("mode") == "offline_information" 

82 assert res.offline_information.lat == 0.1 

83 assert res.offline_information.lng == 0.2 

84 assert res.offline_information.address == "Near Null Island" 

85 assert time_before <= to_aware_datetime(res.created) <= now() 

86 assert time_before <= to_aware_datetime(res.last_edited) <= now() 

87 assert res.creator_user_id == user1.id 

88 assert to_aware_datetime(res.start_time) == start_time 

89 assert to_aware_datetime(res.end_time) == end_time 

90 # assert res.timezone == "UTC" 

91 assert res.start_time_display 

92 assert res.end_time_display 

93 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_GOING 

94 assert res.organizer 

95 assert res.subscriber 

96 assert res.going_count == 1 

97 assert res.maybe_count == 0 

98 assert res.organizer_count == 1 

99 assert res.subscriber_count == 1 

100 assert res.owner_user_id == user1.id 

101 assert not res.owner_community_id 

102 assert not res.owner_group_id 

103 assert res.thread.thread_id 

104 assert res.can_edit 

105 assert not res.can_moderate 

106 

107 event_id = res.event_id 

108 

109 with events_session(token2) as api: 

110 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

111 

112 assert res.is_next 

113 assert res.title == "Dummy Title" 

114 assert res.slug == "dummy-title" 

115 assert res.content == "Dummy content." 

116 assert not res.photo_url 

117 assert res.WhichOneof("mode") == "offline_information" 

118 assert res.offline_information.lat == 0.1 

119 assert res.offline_information.lng == 0.2 

120 assert res.offline_information.address == "Near Null Island" 

121 assert time_before <= to_aware_datetime(res.created) <= now() 

122 assert time_before <= to_aware_datetime(res.last_edited) <= now() 

123 assert res.creator_user_id == user1.id 

124 assert to_aware_datetime(res.start_time) == start_time 

125 assert to_aware_datetime(res.end_time) == end_time 

126 # assert res.timezone == "UTC" 

127 assert res.start_time_display 

128 assert res.end_time_display 

129 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

130 assert not res.organizer 

131 assert not res.subscriber 

132 assert res.going_count == 1 

133 assert res.maybe_count == 0 

134 assert res.organizer_count == 1 

135 assert res.subscriber_count == 1 

136 assert res.owner_user_id == user1.id 

137 assert not res.owner_community_id 

138 assert not res.owner_group_id 

139 assert res.thread.thread_id 

140 assert res.can_edit 

141 assert res.can_moderate 

142 

143 with events_session(token3) as api: 

144 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

145 

146 assert res.is_next 

147 assert res.title == "Dummy Title" 

148 assert res.slug == "dummy-title" 

149 assert res.content == "Dummy content." 

150 assert not res.photo_url 

151 assert res.WhichOneof("mode") == "offline_information" 

152 assert res.offline_information.lat == 0.1 

153 assert res.offline_information.lng == 0.2 

154 assert res.offline_information.address == "Near Null Island" 

155 assert time_before <= to_aware_datetime(res.created) <= now() 

156 assert time_before <= to_aware_datetime(res.last_edited) <= now() 

157 assert res.creator_user_id == user1.id 

158 assert to_aware_datetime(res.start_time) == start_time 

159 assert to_aware_datetime(res.end_time) == end_time 

160 # assert res.timezone == "UTC" 

161 assert res.start_time_display 

162 assert res.end_time_display 

163 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

164 assert not res.organizer 

165 assert not res.subscriber 

166 assert res.going_count == 1 

167 assert res.maybe_count == 0 

168 assert res.organizer_count == 1 

169 assert res.subscriber_count == 1 

170 assert res.owner_user_id == user1.id 

171 assert not res.owner_community_id 

172 assert not res.owner_group_id 

173 assert res.thread.thread_id 

174 assert not res.can_edit 

175 assert not res.can_moderate 

176 

177 with events_session(token1) as api: 

178 # online only event 

179 res = api.CreateEvent( 

180 events_pb2.CreateEventReq( 

181 title="Dummy Title", 

182 content="Dummy content.", 

183 photo_key=None, 

184 online_information=events_pb2.OnlineEventInformation( 

185 link="https://couchers.org/meet/", 

186 ), 

187 parent_community_id=c_id, 

188 start_time=Timestamp_from_datetime(start_time), 

189 end_time=Timestamp_from_datetime(end_time), 

190 timezone="UTC", 

191 ) 

192 ) 

193 

194 assert res.is_next 

195 assert res.title == "Dummy Title" 

196 assert res.slug == "dummy-title" 

197 assert res.content == "Dummy content." 

198 assert not res.photo_url 

199 assert res.WhichOneof("mode") == "online_information" 

200 assert res.online_information.link == "https://couchers.org/meet/" 

201 assert time_before <= to_aware_datetime(res.created) <= now() 

202 assert time_before <= to_aware_datetime(res.last_edited) <= now() 

203 assert res.creator_user_id == user1.id 

204 assert to_aware_datetime(res.start_time) == start_time 

205 assert to_aware_datetime(res.end_time) == end_time 

206 # assert res.timezone == "UTC" 

207 assert res.start_time_display 

208 assert res.end_time_display 

209 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_GOING 

210 assert res.organizer 

211 assert res.subscriber 

212 assert res.going_count == 1 

213 assert res.maybe_count == 0 

214 assert res.organizer_count == 1 

215 assert res.subscriber_count == 1 

216 assert res.owner_user_id == user1.id 

217 assert not res.owner_community_id 

218 assert not res.owner_group_id 

219 assert res.thread.thread_id 

220 assert res.can_edit 

221 assert not res.can_moderate 

222 

223 event_id = res.event_id 

224 

225 with events_session(token2) as api: 

226 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

227 

228 assert res.is_next 

229 assert res.title == "Dummy Title" 

230 assert res.slug == "dummy-title" 

231 assert res.content == "Dummy content." 

232 assert not res.photo_url 

233 assert res.WhichOneof("mode") == "online_information" 

234 assert res.online_information.link == "https://couchers.org/meet/" 

235 assert time_before <= to_aware_datetime(res.created) <= now() 

236 assert time_before <= to_aware_datetime(res.last_edited) <= now() 

237 assert res.creator_user_id == user1.id 

238 assert to_aware_datetime(res.start_time) == start_time 

239 assert to_aware_datetime(res.end_time) == end_time 

240 # assert res.timezone == "UTC" 

241 assert res.start_time_display 

242 assert res.end_time_display 

243 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

244 assert not res.organizer 

245 assert not res.subscriber 

246 assert res.going_count == 1 

247 assert res.maybe_count == 0 

248 assert res.organizer_count == 1 

249 assert res.subscriber_count == 1 

250 assert res.owner_user_id == user1.id 

251 assert not res.owner_community_id 

252 assert not res.owner_group_id 

253 assert res.thread.thread_id 

254 assert res.can_edit 

255 assert res.can_moderate 

256 

257 with events_session(token3) as api: 

258 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

259 

260 assert res.is_next 

261 assert res.title == "Dummy Title" 

262 assert res.slug == "dummy-title" 

263 assert res.content == "Dummy content." 

264 assert not res.photo_url 

265 assert res.WhichOneof("mode") == "online_information" 

266 assert res.online_information.link == "https://couchers.org/meet/" 

267 assert time_before <= to_aware_datetime(res.created) <= now() 

268 assert time_before <= to_aware_datetime(res.last_edited) <= now() 

269 assert res.creator_user_id == user1.id 

270 assert to_aware_datetime(res.start_time) == start_time 

271 assert to_aware_datetime(res.end_time) == end_time 

272 # assert res.timezone == "UTC" 

273 assert res.start_time_display 

274 assert res.end_time_display 

275 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

276 assert not res.organizer 

277 assert not res.subscriber 

278 assert res.going_count == 1 

279 assert res.maybe_count == 0 

280 assert res.organizer_count == 1 

281 assert res.subscriber_count == 1 

282 assert res.owner_user_id == user1.id 

283 assert not res.owner_community_id 

284 assert not res.owner_group_id 

285 assert res.thread.thread_id 

286 assert not res.can_edit 

287 assert not res.can_moderate 

288 

289 with events_session(token1) as api: 

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

291 api.CreateEvent( 

292 events_pb2.CreateEventReq( 

293 title="Dummy Title", 

294 content="Dummy content.", 

295 photo_key=None, 

296 online_information=events_pb2.OnlineEventInformation( 

297 link="https://couchers.org/meet/", 

298 ), 

299 start_time=Timestamp_from_datetime(start_time), 

300 end_time=Timestamp_from_datetime(end_time), 

301 timezone="UTC", 

302 ) 

303 ) 

304 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

305 assert e.value.details() == errors.ONLINE_EVENT_MISSING_PARENT_COMMUNITY 

306 

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

308 api.CreateEvent( 

309 events_pb2.CreateEventReq( 

310 # title="Dummy Title", 

311 content="Dummy content.", 

312 photo_key=None, 

313 offline_information=events_pb2.OfflineEventInformation( 

314 address="Near Null Island", 

315 lat=0.1, 

316 lng=0.1, 

317 ), 

318 start_time=Timestamp_from_datetime(start_time), 

319 end_time=Timestamp_from_datetime(end_time), 

320 timezone="UTC", 

321 ) 

322 ) 

323 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

324 assert e.value.details() == errors.MISSING_EVENT_TITLE 

325 

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

327 api.CreateEvent( 

328 events_pb2.CreateEventReq( 

329 title="Dummy Title", 

330 # content="Dummy content.", 

331 photo_key=None, 

332 offline_information=events_pb2.OfflineEventInformation( 

333 address="Near Null Island", 

334 lat=0.1, 

335 lng=0.1, 

336 ), 

337 start_time=Timestamp_from_datetime(start_time), 

338 end_time=Timestamp_from_datetime(end_time), 

339 timezone="UTC", 

340 ) 

341 ) 

342 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

343 assert e.value.details() == errors.MISSING_EVENT_CONTENT 

344 

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

346 api.CreateEvent( 

347 events_pb2.CreateEventReq( 

348 title="Dummy Title", 

349 content="Dummy content.", 

350 photo_key="nonexistent", 

351 offline_information=events_pb2.OfflineEventInformation( 

352 address="Near Null Island", 

353 lat=0.1, 

354 lng=0.1, 

355 ), 

356 start_time=Timestamp_from_datetime(start_time), 

357 end_time=Timestamp_from_datetime(end_time), 

358 timezone="UTC", 

359 ) 

360 ) 

361 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

362 assert e.value.details() == errors.PHOTO_NOT_FOUND 

363 

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

365 api.CreateEvent( 

366 events_pb2.CreateEventReq( 

367 title="Dummy Title", 

368 content="Dummy content.", 

369 photo_key=None, 

370 offline_information=events_pb2.OfflineEventInformation( 

371 address="Near Null Island", 

372 ), 

373 start_time=Timestamp_from_datetime(start_time), 

374 end_time=Timestamp_from_datetime(end_time), 

375 timezone="UTC", 

376 ) 

377 ) 

378 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

379 assert e.value.details() == errors.MISSING_EVENT_ADDRESS_OR_LOCATION 

380 

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

382 api.CreateEvent( 

383 events_pb2.CreateEventReq( 

384 title="Dummy Title", 

385 content="Dummy content.", 

386 photo_key=None, 

387 offline_information=events_pb2.OfflineEventInformation( 

388 lat=0.1, 

389 lng=0.1, 

390 ), 

391 start_time=Timestamp_from_datetime(start_time), 

392 end_time=Timestamp_from_datetime(end_time), 

393 timezone="UTC", 

394 ) 

395 ) 

396 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

397 assert e.value.details() == errors.MISSING_EVENT_ADDRESS_OR_LOCATION 

398 

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

400 api.CreateEvent( 

401 events_pb2.CreateEventReq( 

402 title="Dummy Title", 

403 content="Dummy content.", 

404 photo_key=None, 

405 online_information=events_pb2.OnlineEventInformation(), 

406 start_time=Timestamp_from_datetime(start_time), 

407 end_time=Timestamp_from_datetime(end_time), 

408 timezone="UTC", 

409 ) 

410 ) 

411 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

412 assert e.value.details() == errors.ONLINE_EVENT_REQUIRES_LINK 

413 

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

415 api.CreateEvent( 

416 events_pb2.CreateEventReq( 

417 title="Dummy Title", 

418 content="Dummy content.", 

419 parent_community_id=c_id, 

420 online_information=events_pb2.OnlineEventInformation( 

421 link="https://couchers.org/meet/", 

422 ), 

423 start_time=Timestamp_from_datetime(now() - timedelta(hours=2)), 

424 end_time=Timestamp_from_datetime(end_time), 

425 timezone="UTC", 

426 ) 

427 ) 

428 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

429 assert e.value.details() == errors.EVENT_IN_PAST 

430 

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

432 api.CreateEvent( 

433 events_pb2.CreateEventReq( 

434 title="Dummy Title", 

435 content="Dummy content.", 

436 parent_community_id=c_id, 

437 online_information=events_pb2.OnlineEventInformation( 

438 link="https://couchers.org/meet/", 

439 ), 

440 start_time=Timestamp_from_datetime(end_time), 

441 end_time=Timestamp_from_datetime(start_time), 

442 timezone="UTC", 

443 ) 

444 ) 

445 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

446 assert e.value.details() == errors.EVENT_ENDS_BEFORE_STARTS 

447 

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

449 api.CreateEvent( 

450 events_pb2.CreateEventReq( 

451 title="Dummy Title", 

452 content="Dummy content.", 

453 parent_community_id=c_id, 

454 online_information=events_pb2.OnlineEventInformation( 

455 link="https://couchers.org/meet/", 

456 ), 

457 start_time=Timestamp_from_datetime(now() + timedelta(days=500, hours=2)), 

458 end_time=Timestamp_from_datetime(now() + timedelta(days=500, hours=5)), 

459 timezone="UTC", 

460 ) 

461 ) 

462 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

463 assert e.value.details() == errors.EVENT_TOO_FAR_IN_FUTURE 

464 

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

466 api.CreateEvent( 

467 events_pb2.CreateEventReq( 

468 title="Dummy Title", 

469 content="Dummy content.", 

470 parent_community_id=c_id, 

471 online_information=events_pb2.OnlineEventInformation( 

472 link="https://couchers.org/meet/", 

473 ), 

474 start_time=Timestamp_from_datetime(start_time), 

475 end_time=Timestamp_from_datetime(now() + timedelta(days=100)), 

476 timezone="UTC", 

477 ) 

478 ) 

479 assert e.value.code() == grpc.StatusCode.INVALID_ARGUMENT 

480 assert e.value.details() == errors.EVENT_TOO_LONG 

481 

482 

483def test_CreateEvent_incomplete_profile(db): 

484 user1, token1 = generate_user(complete_profile=False) 

485 user2, token2 = generate_user() 

486 

487 with session_scope() as session: 

488 c_id = create_community(session, 0, 2, "Community", [user2], [], None).id 

489 

490 start_time = now() + timedelta(hours=2) 

491 end_time = start_time + timedelta(hours=3) 

492 

493 with events_session(token1) as api: 

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

495 api.CreateEvent( 

496 events_pb2.CreateEventReq( 

497 title="Dummy Title", 

498 content="Dummy content.", 

499 photo_key=None, 

500 offline_information=events_pb2.OfflineEventInformation( 

501 address="Near Null Island", 

502 lat=0.1, 

503 lng=0.2, 

504 ), 

505 start_time=Timestamp_from_datetime(start_time), 

506 end_time=Timestamp_from_datetime(end_time), 

507 timezone="UTC", 

508 ) 

509 ) 

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

511 assert e.value.details() == errors.INCOMPLETE_PROFILE_CREATE_EVENT 

512 

513 

514def test_ScheduleEvent(db): 

515 # test cases: 

516 # can schedule a new event occurrence 

517 

518 user, token = generate_user() 

519 

520 with session_scope() as session: 

521 c_id = create_community(session, 0, 2, "Community", [user], [], None).id 

522 

523 time_before = now() 

524 start_time = now() + timedelta(hours=2) 

525 end_time = start_time + timedelta(hours=3) 

526 

527 with events_session(token) as api: 

528 res = api.CreateEvent( 

529 events_pb2.CreateEventReq( 

530 title="Dummy Title", 

531 content="Dummy content.", 

532 parent_community_id=c_id, 

533 online_information=events_pb2.OnlineEventInformation( 

534 link="https://couchers.org/meet/", 

535 ), 

536 start_time=Timestamp_from_datetime(start_time), 

537 end_time=Timestamp_from_datetime(end_time), 

538 timezone="UTC", 

539 ) 

540 ) 

541 

542 new_start_time = now() + timedelta(hours=6) 

543 new_end_time = new_start_time + timedelta(hours=2) 

544 

545 res = api.ScheduleEvent( 

546 events_pb2.ScheduleEventReq( 

547 event_id=res.event_id, 

548 content="New event occurrence", 

549 offline_information=events_pb2.OfflineEventInformation( 

550 address="A bit further but still near Null Island", 

551 lat=0.3, 

552 lng=0.2, 

553 ), 

554 start_time=Timestamp_from_datetime(new_start_time), 

555 end_time=Timestamp_from_datetime(new_end_time), 

556 timezone="UTC", 

557 ) 

558 ) 

559 

560 res = api.GetEvent(events_pb2.GetEventReq(event_id=res.event_id)) 

561 

562 assert not res.is_next 

563 assert res.title == "Dummy Title" 

564 assert res.slug == "dummy-title" 

565 assert res.content == "New event occurrence" 

566 assert not res.photo_url 

567 assert res.WhichOneof("mode") == "offline_information" 

568 assert res.offline_information.lat == 0.3 

569 assert res.offline_information.lng == 0.2 

570 assert res.offline_information.address == "A bit further but still near Null Island" 

571 assert time_before <= to_aware_datetime(res.created) <= now() 

572 assert time_before <= to_aware_datetime(res.last_edited) <= now() 

573 assert res.creator_user_id == user.id 

574 assert to_aware_datetime(res.start_time) == new_start_time 

575 assert to_aware_datetime(res.end_time) == new_end_time 

576 # assert res.timezone == "UTC" 

577 assert res.start_time_display 

578 assert res.end_time_display 

579 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_GOING 

580 assert res.organizer 

581 assert res.subscriber 

582 assert res.going_count == 1 

583 assert res.maybe_count == 0 

584 assert res.organizer_count == 1 

585 assert res.subscriber_count == 1 

586 assert res.owner_user_id == user.id 

587 assert not res.owner_community_id 

588 assert not res.owner_group_id 

589 assert res.thread.thread_id 

590 assert res.can_edit 

591 assert res.can_moderate 

592 

593 

594def test_cannot_overlap_occurrences_schedule(db): 

595 user, token = generate_user() 

596 

597 with session_scope() as session: 

598 c_id = create_community(session, 0, 2, "Community", [user], [], None).id 

599 

600 start = now() 

601 

602 with events_session(token) as api: 

603 res = api.CreateEvent( 

604 events_pb2.CreateEventReq( 

605 title="Dummy Title", 

606 content="Dummy content.", 

607 parent_community_id=c_id, 

608 online_information=events_pb2.OnlineEventInformation( 

609 link="https://couchers.org/meet/", 

610 ), 

611 start_time=Timestamp_from_datetime(start + timedelta(hours=1)), 

612 end_time=Timestamp_from_datetime(start + timedelta(hours=3)), 

613 timezone="UTC", 

614 ) 

615 ) 

616 

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

618 api.ScheduleEvent( 

619 events_pb2.ScheduleEventReq( 

620 event_id=res.event_id, 

621 content="New event occurrence", 

622 offline_information=events_pb2.OfflineEventInformation( 

623 address="A bit further but still near Null Island", 

624 lat=0.3, 

625 lng=0.2, 

626 ), 

627 start_time=Timestamp_from_datetime(start + timedelta(hours=2)), 

628 end_time=Timestamp_from_datetime(start + timedelta(hours=6)), 

629 timezone="UTC", 

630 ) 

631 ) 

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

633 assert e.value.details() == errors.EVENT_CANT_OVERLAP 

634 

635 

636def test_cannot_overlap_occurrences_update(db): 

637 user, token = generate_user() 

638 

639 with session_scope() as session: 

640 c_id = create_community(session, 0, 2, "Community", [user], [], None).id 

641 

642 start = now() 

643 

644 with events_session(token) as api: 

645 res = api.CreateEvent( 

646 events_pb2.CreateEventReq( 

647 title="Dummy Title", 

648 content="Dummy content.", 

649 parent_community_id=c_id, 

650 online_information=events_pb2.OnlineEventInformation( 

651 link="https://couchers.org/meet/", 

652 ), 

653 start_time=Timestamp_from_datetime(start + timedelta(hours=1)), 

654 end_time=Timestamp_from_datetime(start + timedelta(hours=3)), 

655 timezone="UTC", 

656 ) 

657 ) 

658 

659 event_id = api.ScheduleEvent( 

660 events_pb2.ScheduleEventReq( 

661 event_id=res.event_id, 

662 content="New event occurrence", 

663 offline_information=events_pb2.OfflineEventInformation( 

664 address="A bit further but still near Null Island", 

665 lat=0.3, 

666 lng=0.2, 

667 ), 

668 start_time=Timestamp_from_datetime(start + timedelta(hours=4)), 

669 end_time=Timestamp_from_datetime(start + timedelta(hours=6)), 

670 timezone="UTC", 

671 ) 

672 ).event_id 

673 

674 # can overlap with this current existing occurrence 

675 api.UpdateEvent( 

676 events_pb2.UpdateEventReq( 

677 event_id=event_id, 

678 start_time=Timestamp_from_datetime(start + timedelta(hours=5)), 

679 end_time=Timestamp_from_datetime(start + timedelta(hours=6)), 

680 ) 

681 ) 

682 

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

684 api.UpdateEvent( 

685 events_pb2.UpdateEventReq( 

686 event_id=event_id, 

687 start_time=Timestamp_from_datetime(start + timedelta(hours=2)), 

688 end_time=Timestamp_from_datetime(start + timedelta(hours=4)), 

689 ) 

690 ) 

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

692 assert e.value.details() == errors.EVENT_CANT_OVERLAP 

693 

694 

695def test_UpdateEvent_single(db): 

696 # test cases: 

697 # owner can update 

698 # community owner can update 

699 # can't mess up online/in person dichotomy 

700 # notifies attendees 

701 

702 # event creator 

703 user1, token1 = generate_user() 

704 # community moderator 

705 user2, token2 = generate_user() 

706 # third parties 

707 user3, token3 = generate_user() 

708 user4, token4 = generate_user() 

709 user5, token5 = generate_user() 

710 user6, token6 = generate_user() 

711 

712 with session_scope() as session: 

713 c_id = create_community(session, 0, 2, "Community", [user2], [], None).id 

714 

715 time_before = now() 

716 start_time = now() + timedelta(hours=2) 

717 end_time = start_time + timedelta(hours=3) 

718 

719 with events_session(token1) as api: 

720 res = api.CreateEvent( 

721 events_pb2.CreateEventReq( 

722 title="Dummy Title", 

723 content="Dummy content.", 

724 offline_information=events_pb2.OfflineEventInformation( 

725 address="Near Null Island", 

726 lat=0.1, 

727 lng=0.2, 

728 ), 

729 start_time=Timestamp_from_datetime(start_time), 

730 end_time=Timestamp_from_datetime(end_time), 

731 timezone="UTC", 

732 ) 

733 ) 

734 

735 event_id = res.event_id 

736 

737 with events_session(token4) as api: 

738 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True)) 

739 

740 with events_session(token5) as api: 

741 api.SetEventAttendance( 

742 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_GOING) 

743 ) 

744 

745 with events_session(token6) as api: 

746 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True)) 

747 api.SetEventAttendance( 

748 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_MAYBE) 

749 ) 

750 

751 time_before_update = now() 

752 

753 with events_session(token1) as api: 

754 res = api.UpdateEvent( 

755 events_pb2.UpdateEventReq( 

756 event_id=event_id, 

757 ) 

758 ) 

759 

760 with events_session(token1) as api: 

761 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

762 

763 assert res.is_next 

764 assert res.title == "Dummy Title" 

765 assert res.slug == "dummy-title" 

766 assert res.content == "Dummy content." 

767 assert not res.photo_url 

768 assert res.WhichOneof("mode") == "offline_information" 

769 assert res.offline_information.lat == 0.1 

770 assert res.offline_information.lng == 0.2 

771 assert res.offline_information.address == "Near Null Island" 

772 assert time_before <= to_aware_datetime(res.created) <= time_before_update 

773 assert time_before_update <= to_aware_datetime(res.last_edited) <= now() 

774 assert res.creator_user_id == user1.id 

775 assert to_aware_datetime(res.start_time) == start_time 

776 assert to_aware_datetime(res.end_time) == end_time 

777 # assert res.timezone == "UTC" 

778 assert res.start_time_display 

779 assert res.end_time_display 

780 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_GOING 

781 assert res.organizer 

782 assert res.subscriber 

783 assert res.going_count == 2 

784 assert res.maybe_count == 1 

785 assert res.organizer_count == 1 

786 assert res.subscriber_count == 3 

787 assert res.owner_user_id == user1.id 

788 assert not res.owner_community_id 

789 assert not res.owner_group_id 

790 assert res.thread.thread_id 

791 assert res.can_edit 

792 assert not res.can_moderate 

793 

794 with events_session(token2) as api: 

795 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

796 

797 assert res.is_next 

798 assert res.title == "Dummy Title" 

799 assert res.slug == "dummy-title" 

800 assert res.content == "Dummy content." 

801 assert not res.photo_url 

802 assert res.WhichOneof("mode") == "offline_information" 

803 assert res.offline_information.lat == 0.1 

804 assert res.offline_information.lng == 0.2 

805 assert res.offline_information.address == "Near Null Island" 

806 assert time_before <= to_aware_datetime(res.created) <= time_before_update 

807 assert time_before_update <= to_aware_datetime(res.last_edited) <= now() 

808 assert res.creator_user_id == user1.id 

809 assert to_aware_datetime(res.start_time) == start_time 

810 assert to_aware_datetime(res.end_time) == end_time 

811 # assert res.timezone == "UTC" 

812 assert res.start_time_display 

813 assert res.end_time_display 

814 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

815 assert not res.organizer 

816 assert not res.subscriber 

817 assert res.going_count == 2 

818 assert res.maybe_count == 1 

819 assert res.organizer_count == 1 

820 assert res.subscriber_count == 3 

821 assert res.owner_user_id == user1.id 

822 assert not res.owner_community_id 

823 assert not res.owner_group_id 

824 assert res.thread.thread_id 

825 assert res.can_edit 

826 assert res.can_moderate 

827 

828 with events_session(token3) as api: 

829 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

830 

831 assert res.is_next 

832 assert res.title == "Dummy Title" 

833 assert res.slug == "dummy-title" 

834 assert res.content == "Dummy content." 

835 assert not res.photo_url 

836 assert res.WhichOneof("mode") == "offline_information" 

837 assert res.offline_information.lat == 0.1 

838 assert res.offline_information.lng == 0.2 

839 assert res.offline_information.address == "Near Null Island" 

840 assert time_before <= to_aware_datetime(res.created) <= time_before_update 

841 assert time_before_update <= to_aware_datetime(res.last_edited) <= now() 

842 assert res.creator_user_id == user1.id 

843 assert to_aware_datetime(res.start_time) == start_time 

844 assert to_aware_datetime(res.end_time) == end_time 

845 # assert res.timezone == "UTC" 

846 assert res.start_time_display 

847 assert res.end_time_display 

848 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

849 assert not res.organizer 

850 assert not res.subscriber 

851 assert res.going_count == 2 

852 assert res.maybe_count == 1 

853 assert res.organizer_count == 1 

854 assert res.subscriber_count == 3 

855 assert res.owner_user_id == user1.id 

856 assert not res.owner_community_id 

857 assert not res.owner_group_id 

858 assert res.thread.thread_id 

859 assert not res.can_edit 

860 assert not res.can_moderate 

861 

862 with events_session(token1) as api: 

863 res = api.UpdateEvent( 

864 events_pb2.UpdateEventReq( 

865 event_id=event_id, 

866 title=wrappers_pb2.StringValue(value="Dummy Title"), 

867 content=wrappers_pb2.StringValue(value="Dummy content."), 

868 online_information=events_pb2.OnlineEventInformation(link="https://couchers.org/meet/"), 

869 start_time=Timestamp_from_datetime(start_time), 

870 end_time=Timestamp_from_datetime(end_time), 

871 timezone=wrappers_pb2.StringValue(value="UTC"), 

872 ) 

873 ) 

874 

875 assert res.is_next 

876 assert res.title == "Dummy Title" 

877 assert res.slug == "dummy-title" 

878 assert res.content == "Dummy content." 

879 assert not res.photo_url 

880 assert res.WhichOneof("mode") == "online_information" 

881 assert res.online_information.link == "https://couchers.org/meet/" 

882 assert time_before <= to_aware_datetime(res.created) <= time_before_update 

883 assert time_before_update <= to_aware_datetime(res.last_edited) <= now() 

884 assert res.creator_user_id == user1.id 

885 assert to_aware_datetime(res.start_time) == start_time 

886 assert to_aware_datetime(res.end_time) == end_time 

887 # assert res.timezone == "UTC" 

888 assert res.start_time_display 

889 assert res.end_time_display 

890 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_GOING 

891 assert res.organizer 

892 assert res.subscriber 

893 assert res.going_count == 2 

894 assert res.maybe_count == 1 

895 assert res.organizer_count == 1 

896 assert res.subscriber_count == 3 

897 assert res.owner_user_id == user1.id 

898 assert not res.owner_community_id 

899 assert not res.owner_group_id 

900 assert res.thread.thread_id 

901 assert res.can_edit 

902 assert not res.can_moderate 

903 

904 event_id = res.event_id 

905 

906 with events_session(token2) as api: 

907 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

908 

909 assert res.is_next 

910 assert res.title == "Dummy Title" 

911 assert res.slug == "dummy-title" 

912 assert res.content == "Dummy content." 

913 assert not res.photo_url 

914 assert res.WhichOneof("mode") == "online_information" 

915 assert res.online_information.link == "https://couchers.org/meet/" 

916 assert time_before <= to_aware_datetime(res.created) <= time_before_update 

917 assert time_before_update <= to_aware_datetime(res.last_edited) <= now() 

918 assert res.creator_user_id == user1.id 

919 assert to_aware_datetime(res.start_time) == start_time 

920 assert to_aware_datetime(res.end_time) == end_time 

921 # assert res.timezone == "UTC" 

922 assert res.start_time_display 

923 assert res.end_time_display 

924 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

925 assert not res.organizer 

926 assert not res.subscriber 

927 assert res.going_count == 2 

928 assert res.maybe_count == 1 

929 assert res.organizer_count == 1 

930 assert res.subscriber_count == 3 

931 assert res.owner_user_id == user1.id 

932 assert not res.owner_community_id 

933 assert not res.owner_group_id 

934 assert res.thread.thread_id 

935 assert res.can_edit 

936 assert res.can_moderate 

937 

938 with events_session(token3) as api: 

939 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

940 

941 assert res.is_next 

942 assert res.title == "Dummy Title" 

943 assert res.slug == "dummy-title" 

944 assert res.content == "Dummy content." 

945 assert not res.photo_url 

946 assert res.WhichOneof("mode") == "online_information" 

947 assert res.online_information.link == "https://couchers.org/meet/" 

948 assert time_before <= to_aware_datetime(res.created) <= time_before_update 

949 assert time_before_update <= to_aware_datetime(res.last_edited) <= now() 

950 assert res.creator_user_id == user1.id 

951 assert to_aware_datetime(res.start_time) == start_time 

952 assert to_aware_datetime(res.end_time) == end_time 

953 # assert res.timezone == "UTC" 

954 assert res.start_time_display 

955 assert res.end_time_display 

956 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

957 assert not res.organizer 

958 assert not res.subscriber 

959 assert res.going_count == 2 

960 assert res.maybe_count == 1 

961 assert res.organizer_count == 1 

962 assert res.subscriber_count == 3 

963 assert res.owner_user_id == user1.id 

964 assert not res.owner_community_id 

965 assert not res.owner_group_id 

966 assert res.thread.thread_id 

967 assert not res.can_edit 

968 assert not res.can_moderate 

969 

970 with events_session(token1) as api: 

971 res = api.UpdateEvent( 

972 events_pb2.UpdateEventReq( 

973 event_id=event_id, 

974 offline_information=events_pb2.OfflineEventInformation( 

975 address="Near Null Island", 

976 lat=0.1, 

977 lng=0.2, 

978 ), 

979 ) 

980 ) 

981 

982 with events_session(token3) as api: 

983 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

984 

985 assert res.WhichOneof("mode") == "offline_information" 

986 assert res.offline_information.address == "Near Null Island" 

987 assert res.offline_information.lat == 0.1 

988 assert res.offline_information.lng == 0.2 

989 

990 

991def test_UpdateEvent_all(db): 

992 # event creator 

993 user1, token1 = generate_user() 

994 # community moderator 

995 user2, token2 = generate_user() 

996 # third parties 

997 user3, token3 = generate_user() 

998 user4, token4 = generate_user() 

999 user5, token5 = generate_user() 

1000 user6, token6 = generate_user() 

1001 

1002 with session_scope() as session: 

1003 c_id = create_community(session, 0, 2, "Community", [user2], [], None).id 

1004 

1005 time_before = now() 

1006 start_time = now() + timedelta(hours=1) 

1007 end_time = start_time + timedelta(hours=1.5) 

1008 

1009 event_ids = [] 

1010 

1011 with events_session(token1) as api: 

1012 res = api.CreateEvent( 

1013 events_pb2.CreateEventReq( 

1014 title="Dummy Title", 

1015 content="0th occurrence", 

1016 offline_information=events_pb2.OfflineEventInformation( 

1017 address="Near Null Island", 

1018 lat=0.1, 

1019 lng=0.2, 

1020 ), 

1021 start_time=Timestamp_from_datetime(start_time), 

1022 end_time=Timestamp_from_datetime(end_time), 

1023 timezone="UTC", 

1024 ) 

1025 ) 

1026 

1027 event_id = res.event_id 

1028 event_ids.append(event_id) 

1029 

1030 with events_session(token4) as api: 

1031 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True)) 

1032 

1033 with events_session(token5) as api: 

1034 api.SetEventAttendance( 

1035 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_GOING) 

1036 ) 

1037 

1038 with events_session(token6) as api: 

1039 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True)) 

1040 api.SetEventAttendance( 

1041 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_MAYBE) 

1042 ) 

1043 

1044 with events_session(token1) as api: 

1045 for i in range(5): 

1046 res = api.ScheduleEvent( 

1047 events_pb2.ScheduleEventReq( 

1048 event_id=event_ids[-1], 

1049 content=f"{i + 1}th occurrence", 

1050 online_information=events_pb2.OnlineEventInformation( 

1051 link="https://couchers.org/meet/", 

1052 ), 

1053 start_time=Timestamp_from_datetime(start_time + timedelta(hours=2 + i)), 

1054 end_time=Timestamp_from_datetime(start_time + timedelta(hours=2.5 + i)), 

1055 timezone="UTC", 

1056 ) 

1057 ) 

1058 

1059 event_ids.append(res.event_id) 

1060 

1061 updated_event_id = event_ids[3] 

1062 

1063 time_before_update = now() 

1064 

1065 with events_session(token1) as api: 

1066 res = api.UpdateEvent( 

1067 events_pb2.UpdateEventReq( 

1068 event_id=updated_event_id, 

1069 title=wrappers_pb2.StringValue(value="New Title"), 

1070 content=wrappers_pb2.StringValue(value="New content."), 

1071 online_information=events_pb2.OnlineEventInformation(link="https://couchers.org/meet/"), 

1072 update_all_future=True, 

1073 ) 

1074 ) 

1075 

1076 time_after_update = now() 

1077 

1078 with events_session(token2) as api: 

1079 for i in range(3): 

1080 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_ids[i])) 

1081 assert res.content == f"{i}th occurrence" 

1082 assert time_before <= to_aware_datetime(res.last_edited) <= time_before_update 

1083 

1084 for i in range(3, 6): 

1085 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_ids[i])) 

1086 assert res.content == "New content." 

1087 assert time_before_update <= to_aware_datetime(res.last_edited) <= time_after_update 

1088 

1089 

1090def test_GetEvent(db): 

1091 # event creator 

1092 user1, token1 = generate_user() 

1093 # community moderator 

1094 user2, token2 = generate_user() 

1095 # third parties 

1096 user3, token3 = generate_user() 

1097 user4, token4 = generate_user() 

1098 user5, token5 = generate_user() 

1099 user6, token6 = generate_user() 

1100 

1101 with session_scope() as session: 

1102 c_id = create_community(session, 0, 2, "Community", [user2], [], None).id 

1103 

1104 time_before = now() 

1105 start_time = now() + timedelta(hours=2) 

1106 end_time = start_time + timedelta(hours=3) 

1107 

1108 with events_session(token1) as api: 

1109 # in person event 

1110 res = api.CreateEvent( 

1111 events_pb2.CreateEventReq( 

1112 title="Dummy Title", 

1113 content="Dummy content.", 

1114 offline_information=events_pb2.OfflineEventInformation( 

1115 address="Near Null Island", 

1116 lat=0.1, 

1117 lng=0.2, 

1118 ), 

1119 start_time=Timestamp_from_datetime(start_time), 

1120 end_time=Timestamp_from_datetime(end_time), 

1121 timezone="UTC", 

1122 ) 

1123 ) 

1124 

1125 event_id = res.event_id 

1126 

1127 with events_session(token4) as api: 

1128 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True)) 

1129 

1130 with events_session(token5) as api: 

1131 api.SetEventAttendance( 

1132 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_GOING) 

1133 ) 

1134 

1135 with events_session(token6) as api: 

1136 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True)) 

1137 api.SetEventAttendance( 

1138 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_MAYBE) 

1139 ) 

1140 

1141 with events_session(token1) as api: 

1142 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

1143 

1144 assert res.is_next 

1145 assert res.title == "Dummy Title" 

1146 assert res.slug == "dummy-title" 

1147 assert res.content == "Dummy content." 

1148 assert not res.photo_url 

1149 assert res.WhichOneof("mode") == "offline_information" 

1150 assert res.offline_information.lat == 0.1 

1151 assert res.offline_information.lng == 0.2 

1152 assert res.offline_information.address == "Near Null Island" 

1153 assert time_before <= to_aware_datetime(res.created) <= now() 

1154 assert time_before <= to_aware_datetime(res.last_edited) <= now() 

1155 assert res.creator_user_id == user1.id 

1156 assert to_aware_datetime(res.start_time) == start_time 

1157 assert to_aware_datetime(res.end_time) == end_time 

1158 # assert res.timezone == "UTC" 

1159 assert res.start_time_display 

1160 assert res.end_time_display 

1161 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_GOING 

1162 assert res.organizer 

1163 assert res.subscriber 

1164 assert res.going_count == 2 

1165 assert res.maybe_count == 1 

1166 assert res.organizer_count == 1 

1167 assert res.subscriber_count == 3 

1168 assert res.owner_user_id == user1.id 

1169 assert not res.owner_community_id 

1170 assert not res.owner_group_id 

1171 assert res.thread.thread_id 

1172 assert res.can_edit 

1173 assert not res.can_moderate 

1174 

1175 with events_session(token2) as api: 

1176 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

1177 

1178 assert res.is_next 

1179 assert res.title == "Dummy Title" 

1180 assert res.slug == "dummy-title" 

1181 assert res.content == "Dummy content." 

1182 assert not res.photo_url 

1183 assert res.WhichOneof("mode") == "offline_information" 

1184 assert res.offline_information.lat == 0.1 

1185 assert res.offline_information.lng == 0.2 

1186 assert res.offline_information.address == "Near Null Island" 

1187 assert time_before <= to_aware_datetime(res.created) <= now() 

1188 assert time_before <= to_aware_datetime(res.last_edited) <= now() 

1189 assert res.creator_user_id == user1.id 

1190 assert to_aware_datetime(res.start_time) == start_time 

1191 assert to_aware_datetime(res.end_time) == end_time 

1192 # assert res.timezone == "UTC" 

1193 assert res.start_time_display 

1194 assert res.end_time_display 

1195 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

1196 assert not res.organizer 

1197 assert not res.subscriber 

1198 assert res.going_count == 2 

1199 assert res.maybe_count == 1 

1200 assert res.organizer_count == 1 

1201 assert res.subscriber_count == 3 

1202 assert res.owner_user_id == user1.id 

1203 assert not res.owner_community_id 

1204 assert not res.owner_group_id 

1205 assert res.thread.thread_id 

1206 assert res.can_edit 

1207 assert res.can_moderate 

1208 

1209 with events_session(token3) as api: 

1210 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

1211 

1212 assert res.is_next 

1213 assert res.title == "Dummy Title" 

1214 assert res.slug == "dummy-title" 

1215 assert res.content == "Dummy content." 

1216 assert not res.photo_url 

1217 assert res.WhichOneof("mode") == "offline_information" 

1218 assert res.offline_information.lat == 0.1 

1219 assert res.offline_information.lng == 0.2 

1220 assert res.offline_information.address == "Near Null Island" 

1221 assert time_before <= to_aware_datetime(res.created) <= now() 

1222 assert time_before <= to_aware_datetime(res.last_edited) <= now() 

1223 assert res.creator_user_id == user1.id 

1224 assert to_aware_datetime(res.start_time) == start_time 

1225 assert to_aware_datetime(res.end_time) == end_time 

1226 # assert res.timezone == "UTC" 

1227 assert res.start_time_display 

1228 assert res.end_time_display 

1229 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

1230 assert not res.organizer 

1231 assert not res.subscriber 

1232 assert res.going_count == 2 

1233 assert res.maybe_count == 1 

1234 assert res.organizer_count == 1 

1235 assert res.subscriber_count == 3 

1236 assert res.owner_user_id == user1.id 

1237 assert not res.owner_community_id 

1238 assert not res.owner_group_id 

1239 assert res.thread.thread_id 

1240 assert not res.can_edit 

1241 assert not res.can_moderate 

1242 

1243 

1244def test_CancelEvent(db): 

1245 # event creator 

1246 user1, token1 = generate_user() 

1247 # community moderator 

1248 user2, token2 = generate_user() 

1249 # third parties 

1250 user3, token3 = generate_user() 

1251 user4, token4 = generate_user() 

1252 user5, token5 = generate_user() 

1253 user6, token6 = generate_user() 

1254 

1255 with session_scope() as session: 

1256 c_id = create_community(session, 0, 2, "Community", [user2], [], None).id 

1257 

1258 start_time = now() + timedelta(hours=2) 

1259 end_time = start_time + timedelta(hours=3) 

1260 

1261 with events_session(token1) as api: 

1262 res = api.CreateEvent( 

1263 events_pb2.CreateEventReq( 

1264 title="Dummy Title", 

1265 content="Dummy content.", 

1266 offline_information=events_pb2.OfflineEventInformation( 

1267 address="Near Null Island", 

1268 lat=0.1, 

1269 lng=0.2, 

1270 ), 

1271 start_time=Timestamp_from_datetime(start_time), 

1272 end_time=Timestamp_from_datetime(end_time), 

1273 timezone="UTC", 

1274 ) 

1275 ) 

1276 

1277 event_id = res.event_id 

1278 

1279 with events_session(token4) as api: 

1280 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True)) 

1281 

1282 with events_session(token5) as api: 

1283 api.SetEventAttendance( 

1284 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_GOING) 

1285 ) 

1286 

1287 with events_session(token6) as api: 

1288 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True)) 

1289 api.SetEventAttendance( 

1290 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_MAYBE) 

1291 ) 

1292 

1293 with events_session(token1) as api: 

1294 res = api.CancelEvent( 

1295 events_pb2.CancelEventReq( 

1296 event_id=event_id, 

1297 ) 

1298 ) 

1299 

1300 with events_session(token1) as api: 

1301 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

1302 assert res.is_cancelled 

1303 

1304 with events_session(token1) as api: 

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

1306 api.UpdateEvent( 

1307 events_pb2.UpdateEventReq( 

1308 event_id=event_id, 

1309 title=wrappers_pb2.StringValue(value="New Title"), 

1310 ) 

1311 ) 

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

1313 assert e.value.details() == errors.EVENT_CANT_UPDATE_CANCELLED_EVENT 

1314 

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

1316 api.InviteEventOrganizer( 

1317 events_pb2.InviteEventOrganizerReq( 

1318 event_id=event_id, 

1319 user_id=user3.id, 

1320 ) 

1321 ) 

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

1323 assert e.value.details() == errors.EVENT_CANT_UPDATE_CANCELLED_EVENT 

1324 

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

1326 api.TransferEvent(events_pb2.TransferEventReq(event_id=event_id, new_owner_community_id=c_id)) 

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

1328 assert e.value.details() == errors.EVENT_CANT_UPDATE_CANCELLED_EVENT 

1329 

1330 with events_session(token3) as api: 

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

1332 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True)) 

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

1334 assert e.value.details() == errors.EVENT_CANT_UPDATE_CANCELLED_EVENT 

1335 

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

1337 api.SetEventAttendance( 

1338 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_GOING) 

1339 ) 

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

1341 assert e.value.details() == errors.EVENT_CANT_UPDATE_CANCELLED_EVENT 

1342 

1343 with events_session(token1) as api: 

1344 for include_cancelled in [True, False]: 

1345 res = api.ListEventOccurrences( 

1346 events_pb2.ListEventOccurrencesReq( 

1347 event_id=event_id, 

1348 include_cancelled=include_cancelled, 

1349 ) 

1350 ) 

1351 if include_cancelled: 

1352 assert len(res.events) > 0 

1353 else: 

1354 assert len(res.events) == 0 

1355 

1356 res = api.ListMyEvents( 

1357 events_pb2.ListMyEventsReq( 

1358 include_cancelled=include_cancelled, 

1359 ) 

1360 ) 

1361 if include_cancelled: 

1362 assert len(res.events) > 0 

1363 else: 

1364 assert len(res.events) == 0 

1365 

1366 

1367def test_ListEventAttendees(db): 

1368 # event creator 

1369 user1, token1 = generate_user() 

1370 # others 

1371 user2, token2 = generate_user() 

1372 user3, token3 = generate_user() 

1373 user4, token4 = generate_user() 

1374 user5, token5 = generate_user() 

1375 user6, token6 = generate_user() 

1376 

1377 with session_scope() as session: 

1378 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id 

1379 

1380 with events_session(token1) as api: 

1381 event_id = api.CreateEvent( 

1382 events_pb2.CreateEventReq( 

1383 title="Dummy Title", 

1384 content="Dummy content.", 

1385 offline_information=events_pb2.OfflineEventInformation( 

1386 address="Near Null Island", 

1387 lat=0.1, 

1388 lng=0.2, 

1389 ), 

1390 start_time=Timestamp_from_datetime(now() + timedelta(hours=2)), 

1391 end_time=Timestamp_from_datetime(now() + timedelta(hours=5)), 

1392 timezone="UTC", 

1393 ) 

1394 ).event_id 

1395 

1396 for token in [token2, token3, token4, token5]: 

1397 with events_session(token) as api: 

1398 api.SetEventAttendance( 

1399 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_GOING) 

1400 ) 

1401 

1402 with events_session(token6) as api: 

1403 assert api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).going_count == 5 

1404 

1405 res = api.ListEventAttendees(events_pb2.ListEventAttendeesReq(event_id=event_id, page_size=2)) 

1406 assert res.attendee_user_ids == [user1.id, user2.id] 

1407 

1408 res = api.ListEventAttendees( 

1409 events_pb2.ListEventAttendeesReq(event_id=event_id, page_size=2, page_token=res.next_page_token) 

1410 ) 

1411 assert res.attendee_user_ids == [user3.id, user4.id] 

1412 

1413 res = api.ListEventAttendees( 

1414 events_pb2.ListEventAttendeesReq(event_id=event_id, page_size=2, page_token=res.next_page_token) 

1415 ) 

1416 assert res.attendee_user_ids == [user5.id] 

1417 assert not res.next_page_token 

1418 

1419 

1420def test_ListEventSubscribers(db): 

1421 # event creator 

1422 user1, token1 = generate_user() 

1423 # others 

1424 user2, token2 = generate_user() 

1425 user3, token3 = generate_user() 

1426 user4, token4 = generate_user() 

1427 user5, token5 = generate_user() 

1428 user6, token6 = generate_user() 

1429 

1430 with session_scope() as session: 

1431 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id 

1432 

1433 with events_session(token1) as api: 

1434 event_id = api.CreateEvent( 

1435 events_pb2.CreateEventReq( 

1436 title="Dummy Title", 

1437 content="Dummy content.", 

1438 offline_information=events_pb2.OfflineEventInformation( 

1439 address="Near Null Island", 

1440 lat=0.1, 

1441 lng=0.2, 

1442 ), 

1443 start_time=Timestamp_from_datetime(now() + timedelta(hours=2)), 

1444 end_time=Timestamp_from_datetime(now() + timedelta(hours=5)), 

1445 timezone="UTC", 

1446 ) 

1447 ).event_id 

1448 

1449 for token in [token2, token3, token4, token5]: 

1450 with events_session(token) as api: 

1451 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True)) 

1452 

1453 with events_session(token6) as api: 

1454 assert api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).subscriber_count == 5 

1455 

1456 res = api.ListEventSubscribers(events_pb2.ListEventSubscribersReq(event_id=event_id, page_size=2)) 

1457 assert res.subscriber_user_ids == [user1.id, user2.id] 

1458 

1459 res = api.ListEventSubscribers( 

1460 events_pb2.ListEventSubscribersReq(event_id=event_id, page_size=2, page_token=res.next_page_token) 

1461 ) 

1462 assert res.subscriber_user_ids == [user3.id, user4.id] 

1463 

1464 res = api.ListEventSubscribers( 

1465 events_pb2.ListEventSubscribersReq(event_id=event_id, page_size=2, page_token=res.next_page_token) 

1466 ) 

1467 assert res.subscriber_user_ids == [user5.id] 

1468 assert not res.next_page_token 

1469 

1470 

1471def test_ListEventOrganizers(db): 

1472 # event creator 

1473 user1, token1 = generate_user() 

1474 # others 

1475 user2, token2 = generate_user() 

1476 user3, token3 = generate_user() 

1477 user4, token4 = generate_user() 

1478 user5, token5 = generate_user() 

1479 user6, token6 = generate_user() 

1480 

1481 with session_scope() as session: 

1482 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id 

1483 

1484 with events_session(token1) as api: 

1485 event_id = api.CreateEvent( 

1486 events_pb2.CreateEventReq( 

1487 title="Dummy Title", 

1488 content="Dummy content.", 

1489 offline_information=events_pb2.OfflineEventInformation( 

1490 address="Near Null Island", 

1491 lat=0.1, 

1492 lng=0.2, 

1493 ), 

1494 start_time=Timestamp_from_datetime(now() + timedelta(hours=2)), 

1495 end_time=Timestamp_from_datetime(now() + timedelta(hours=5)), 

1496 timezone="UTC", 

1497 ) 

1498 ).event_id 

1499 

1500 with events_session(token1) as api: 

1501 for user_id in [user2.id, user3.id, user4.id, user5.id]: 

1502 api.InviteEventOrganizer(events_pb2.InviteEventOrganizerReq(event_id=event_id, user_id=user_id)) 

1503 

1504 with events_session(token6) as api: 

1505 assert api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).organizer_count == 5 

1506 

1507 res = api.ListEventOrganizers(events_pb2.ListEventOrganizersReq(event_id=event_id, page_size=2)) 

1508 assert res.organizer_user_ids == [user1.id, user2.id] 

1509 

1510 res = api.ListEventOrganizers( 

1511 events_pb2.ListEventOrganizersReq(event_id=event_id, page_size=2, page_token=res.next_page_token) 

1512 ) 

1513 assert res.organizer_user_ids == [user3.id, user4.id] 

1514 

1515 res = api.ListEventOrganizers( 

1516 events_pb2.ListEventOrganizersReq(event_id=event_id, page_size=2, page_token=res.next_page_token) 

1517 ) 

1518 assert res.organizer_user_ids == [user5.id] 

1519 assert not res.next_page_token 

1520 

1521 

1522def test_TransferEvent(db): 

1523 user1, token1 = generate_user() 

1524 user2, token2 = generate_user() 

1525 user3, token3 = generate_user() 

1526 user4, token4 = generate_user() 

1527 

1528 with session_scope() as session: 

1529 c = create_community(session, 0, 2, "Community", [user3], [], None) 

1530 h = create_group(session, "Group", [user4], [], c) 

1531 c_id = c.id 

1532 h_id = h.id 

1533 

1534 with events_session(token1) as api: 

1535 event_id = api.CreateEvent( 

1536 events_pb2.CreateEventReq( 

1537 title="Dummy Title", 

1538 content="Dummy content.", 

1539 offline_information=events_pb2.OfflineEventInformation( 

1540 address="Near Null Island", 

1541 lat=0.1, 

1542 lng=0.2, 

1543 ), 

1544 start_time=Timestamp_from_datetime(now() + timedelta(hours=2)), 

1545 end_time=Timestamp_from_datetime(now() + timedelta(hours=5)), 

1546 timezone="UTC", 

1547 ) 

1548 ).event_id 

1549 

1550 api.TransferEvent( 

1551 events_pb2.TransferEventReq( 

1552 event_id=event_id, 

1553 new_owner_community_id=c_id, 

1554 ) 

1555 ) 

1556 

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

1558 api.TransferEvent( 

1559 events_pb2.TransferEventReq( 

1560 event_id=event_id, 

1561 new_owner_group_id=h_id, 

1562 ) 

1563 ) 

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

1565 assert e.value.details() == errors.EVENT_TRANSFER_PERMISSION_DENIED 

1566 

1567 event_id = api.CreateEvent( 

1568 events_pb2.CreateEventReq( 

1569 title="Dummy Title", 

1570 content="Dummy content.", 

1571 offline_information=events_pb2.OfflineEventInformation( 

1572 address="Near Null Island", 

1573 lat=0.1, 

1574 lng=0.2, 

1575 ), 

1576 start_time=Timestamp_from_datetime(now() + timedelta(hours=2)), 

1577 end_time=Timestamp_from_datetime(now() + timedelta(hours=5)), 

1578 timezone="UTC", 

1579 ) 

1580 ).event_id 

1581 

1582 api.TransferEvent( 

1583 events_pb2.TransferEventReq( 

1584 event_id=event_id, 

1585 new_owner_group_id=h_id, 

1586 ) 

1587 ) 

1588 

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

1590 api.TransferEvent( 

1591 events_pb2.TransferEventReq( 

1592 event_id=event_id, 

1593 new_owner_community_id=c_id, 

1594 ) 

1595 ) 

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

1597 assert e.value.details() == errors.EVENT_TRANSFER_PERMISSION_DENIED 

1598 

1599 

1600def test_SetEventSubscription(db): 

1601 user1, token1 = generate_user() 

1602 user2, token2 = generate_user() 

1603 

1604 with session_scope() as session: 

1605 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id 

1606 

1607 with events_session(token1) as api: 

1608 event_id = api.CreateEvent( 

1609 events_pb2.CreateEventReq( 

1610 title="Dummy Title", 

1611 content="Dummy content.", 

1612 offline_information=events_pb2.OfflineEventInformation( 

1613 address="Near Null Island", 

1614 lat=0.1, 

1615 lng=0.2, 

1616 ), 

1617 start_time=Timestamp_from_datetime(now() + timedelta(hours=2)), 

1618 end_time=Timestamp_from_datetime(now() + timedelta(hours=5)), 

1619 timezone="UTC", 

1620 ) 

1621 ).event_id 

1622 

1623 with events_session(token2) as api: 

1624 assert not api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).subscriber 

1625 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True)) 

1626 assert api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).subscriber 

1627 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=False)) 

1628 assert not api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).subscriber 

1629 

1630 

1631def test_SetEventAttendance(db): 

1632 user1, token1 = generate_user() 

1633 user2, token2 = generate_user() 

1634 

1635 with session_scope() as session: 

1636 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id 

1637 

1638 with events_session(token1) as api: 

1639 event_id = api.CreateEvent( 

1640 events_pb2.CreateEventReq( 

1641 title="Dummy Title", 

1642 content="Dummy content.", 

1643 offline_information=events_pb2.OfflineEventInformation( 

1644 address="Near Null Island", 

1645 lat=0.1, 

1646 lng=0.2, 

1647 ), 

1648 start_time=Timestamp_from_datetime(now() + timedelta(hours=2)), 

1649 end_time=Timestamp_from_datetime(now() + timedelta(hours=5)), 

1650 timezone="UTC", 

1651 ) 

1652 ).event_id 

1653 

1654 with events_session(token2) as api: 

1655 assert ( 

1656 api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).attendance_state 

1657 == events_pb2.ATTENDANCE_STATE_NOT_GOING 

1658 ) 

1659 api.SetEventAttendance( 

1660 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_GOING) 

1661 ) 

1662 assert ( 

1663 api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).attendance_state 

1664 == events_pb2.ATTENDANCE_STATE_GOING 

1665 ) 

1666 api.SetEventAttendance( 

1667 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_MAYBE) 

1668 ) 

1669 assert ( 

1670 api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).attendance_state 

1671 == events_pb2.ATTENDANCE_STATE_MAYBE 

1672 ) 

1673 api.SetEventAttendance( 

1674 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_NOT_GOING) 

1675 ) 

1676 assert ( 

1677 api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).attendance_state 

1678 == events_pb2.ATTENDANCE_STATE_NOT_GOING 

1679 ) 

1680 

1681 

1682def test_InviteEventOrganizer(db): 

1683 user1, token1 = generate_user() 

1684 user2, token2 = generate_user() 

1685 

1686 with session_scope() as session: 

1687 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id 

1688 

1689 with events_session(token1) as api: 

1690 event_id = api.CreateEvent( 

1691 events_pb2.CreateEventReq( 

1692 title="Dummy Title", 

1693 content="Dummy content.", 

1694 offline_information=events_pb2.OfflineEventInformation( 

1695 address="Near Null Island", 

1696 lat=0.1, 

1697 lng=0.2, 

1698 ), 

1699 start_time=Timestamp_from_datetime(now() + timedelta(hours=2)), 

1700 end_time=Timestamp_from_datetime(now() + timedelta(hours=5)), 

1701 timezone="UTC", 

1702 ) 

1703 ).event_id 

1704 

1705 with events_session(token2) as api: 

1706 assert not api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).organizer 

1707 

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

1709 api.InviteEventOrganizer(events_pb2.InviteEventOrganizerReq(event_id=event_id, user_id=user1.id)) 

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

1711 assert e.value.details() == errors.EVENT_EDIT_PERMISSION_DENIED 

1712 

1713 assert not api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).organizer 

1714 

1715 with events_session(token1) as api: 

1716 api.InviteEventOrganizer(events_pb2.InviteEventOrganizerReq(event_id=event_id, user_id=user2.id)) 

1717 

1718 with events_session(token2) as api: 

1719 assert api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).organizer 

1720 

1721 

1722def test_ListEventOccurrences(db): 

1723 user1, token1 = generate_user() 

1724 user2, token2 = generate_user() 

1725 user3, token3 = generate_user() 

1726 

1727 with session_scope() as session: 

1728 c_id = create_community(session, 0, 2, "Community", [user2], [], None).id 

1729 

1730 start = now() 

1731 

1732 event_ids = [] 

1733 

1734 with events_session(token1) as api: 

1735 res = api.CreateEvent( 

1736 events_pb2.CreateEventReq( 

1737 title="First occurrence", 

1738 content="Dummy content.", 

1739 parent_community_id=c_id, 

1740 online_information=events_pb2.OnlineEventInformation( 

1741 link="https://couchers.org/meet/", 

1742 ), 

1743 start_time=Timestamp_from_datetime(start + timedelta(hours=1)), 

1744 end_time=Timestamp_from_datetime(start + timedelta(hours=1.5)), 

1745 timezone="UTC", 

1746 ) 

1747 ) 

1748 

1749 event_ids.append(res.event_id) 

1750 

1751 for i in range(5): 

1752 res = api.ScheduleEvent( 

1753 events_pb2.ScheduleEventReq( 

1754 event_id=event_ids[-1], 

1755 content=f"{i}th occurrence", 

1756 online_information=events_pb2.OnlineEventInformation( 

1757 link="https://couchers.org/meet/", 

1758 ), 

1759 start_time=Timestamp_from_datetime(start + timedelta(hours=2 + i)), 

1760 end_time=Timestamp_from_datetime(start + timedelta(hours=2.5 + i)), 

1761 timezone="UTC", 

1762 ) 

1763 ) 

1764 

1765 event_ids.append(res.event_id) 

1766 

1767 res = api.ListEventOccurrences(events_pb2.ListEventOccurrencesReq(event_id=event_ids[-1], page_size=2)) 

1768 assert [event.event_id for event in res.events] == event_ids[:2] 

1769 

1770 res = api.ListEventOccurrences( 

1771 events_pb2.ListEventOccurrencesReq(event_id=event_ids[-1], page_size=2, page_token=res.next_page_token) 

1772 ) 

1773 assert [event.event_id for event in res.events] == event_ids[2:4] 

1774 

1775 res = api.ListEventOccurrences( 

1776 events_pb2.ListEventOccurrencesReq(event_id=event_ids[-1], page_size=2, page_token=res.next_page_token) 

1777 ) 

1778 assert [event.event_id for event in res.events] == event_ids[4:6] 

1779 assert not res.next_page_token 

1780 

1781 

1782def test_ListMyEvents(db): 

1783 user1, token1 = generate_user() 

1784 user2, token2 = generate_user() 

1785 user3, token3 = generate_user() 

1786 user4, token4 = generate_user() 

1787 user5, token5 = generate_user() 

1788 

1789 with session_scope() as session: 

1790 c_id = create_community(session, 0, 2, "Community", [user3], [], None).id 

1791 c2_id = create_community(session, 0, 2, "Community", [user4], [], None).id 

1792 

1793 start = now() 

1794 

1795 def new_event(hours_from_now, community_id, online=True): 

1796 if online: 

1797 return events_pb2.CreateEventReq( 

1798 title="Dummy Online Title", 

1799 content="Dummy content.", 

1800 online_information=events_pb2.OnlineEventInformation( 

1801 link="https://couchers.org/meet/", 

1802 ), 

1803 parent_community_id=community_id, 

1804 timezone="UTC", 

1805 start_time=Timestamp_from_datetime(start + timedelta(hours=hours_from_now)), 

1806 end_time=Timestamp_from_datetime(start + timedelta(hours=hours_from_now + 0.5)), 

1807 ) 

1808 else: 

1809 return events_pb2.CreateEventReq( 

1810 title="Dummy Offline Title", 

1811 content="Dummy content.", 

1812 offline_information=events_pb2.OfflineEventInformation( 

1813 address="Near Null Island", 

1814 lat=0.1, 

1815 lng=0.2, 

1816 ), 

1817 timezone="UTC", 

1818 start_time=Timestamp_from_datetime(start + timedelta(hours=hours_from_now)), 

1819 end_time=Timestamp_from_datetime(start + timedelta(hours=hours_from_now + 0.5)), 

1820 ) 

1821 

1822 with events_session(token1) as api: 

1823 e2 = api.CreateEvent(new_event(2, c_id, True)).event_id 

1824 

1825 with events_session(token2) as api: 

1826 e1 = api.CreateEvent(new_event(1, c_id, False)).event_id 

1827 

1828 with events_session(token1) as api: 

1829 e3 = api.CreateEvent(new_event(3, c_id, False)).event_id 

1830 

1831 with events_session(token2) as api: 

1832 e5 = api.CreateEvent(new_event(5, c_id, True)).event_id 

1833 

1834 with events_session(token3) as api: 

1835 e4 = api.CreateEvent(new_event(4, c_id, True)).event_id 

1836 

1837 with events_session(token4) as api: 

1838 e6 = api.CreateEvent(new_event(6, c2_id, True)).event_id 

1839 

1840 with events_session(token1) as api: 

1841 api.InviteEventOrganizer(events_pb2.InviteEventOrganizerReq(event_id=e3, user_id=user3.id)) 

1842 

1843 with events_session(token1) as api: 

1844 api.SetEventAttendance( 

1845 events_pb2.SetEventAttendanceReq(event_id=e1, attendance_state=events_pb2.ATTENDANCE_STATE_MAYBE) 

1846 ) 

1847 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=e4, subscribe=True)) 

1848 

1849 with events_session(token2) as api: 

1850 api.SetEventAttendance( 

1851 events_pb2.SetEventAttendanceReq(event_id=e3, attendance_state=events_pb2.ATTENDANCE_STATE_GOING) 

1852 ) 

1853 

1854 with events_session(token3) as api: 

1855 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=e2, subscribe=True)) 

1856 

1857 with events_session(token1) as api: 

1858 # test pagination with token first 

1859 res = api.ListMyEvents(events_pb2.ListMyEventsReq(page_size=2)) 

1860 assert [event.event_id for event in res.events] == [e1, e2] 

1861 res = api.ListMyEvents(events_pb2.ListMyEventsReq(page_size=2, page_token=res.next_page_token)) 

1862 assert [event.event_id for event in res.events] == [e3, e4] 

1863 assert not res.next_page_token 

1864 

1865 res = api.ListMyEvents( 

1866 events_pb2.ListMyEventsReq( 

1867 subscribed=True, 

1868 attending=True, 

1869 organizing=True, 

1870 ) 

1871 ) 

1872 assert [event.event_id for event in res.events] == [e1, e2, e3, e4] 

1873 

1874 res = api.ListMyEvents(events_pb2.ListMyEventsReq()) 

1875 assert [event.event_id for event in res.events] == [e1, e2, e3, e4] 

1876 

1877 res = api.ListMyEvents(events_pb2.ListMyEventsReq(subscribed=True)) 

1878 assert [event.event_id for event in res.events] == [e2, e3, e4] 

1879 

1880 res = api.ListMyEvents(events_pb2.ListMyEventsReq(attending=True)) 

1881 assert [event.event_id for event in res.events] == [e1, e2, e3] 

1882 

1883 res = api.ListMyEvents(events_pb2.ListMyEventsReq(organizing=True)) 

1884 assert [event.event_id for event in res.events] == [e2, e3] 

1885 

1886 with events_session(token1) as api: 

1887 # Test pagination with page_number and verify total_items 

1888 res = api.ListMyEvents( 

1889 events_pb2.ListMyEventsReq(page_size=2, page_number=1, subscribed=True, attending=True, organizing=True) 

1890 ) 

1891 assert [event.event_id for event in res.events] == [e1, e2] 

1892 assert res.total_items == 4 

1893 

1894 res = api.ListMyEvents( 

1895 events_pb2.ListMyEventsReq(page_size=2, page_number=2, subscribed=True, attending=True, organizing=True) 

1896 ) 

1897 assert [event.event_id for event in res.events] == [e3, e4] 

1898 assert res.total_items == 4 

1899 

1900 # Verify no more pages 

1901 res = api.ListMyEvents( 

1902 events_pb2.ListMyEventsReq(page_size=2, page_number=3, subscribed=True, attending=True, organizing=True) 

1903 ) 

1904 assert not res.events 

1905 assert res.total_items == 4 

1906 

1907 with events_session(token2) as api: 

1908 res = api.ListMyEvents(events_pb2.ListMyEventsReq()) 

1909 assert [event.event_id for event in res.events] == [e1, e3, e5] 

1910 

1911 res = api.ListMyEvents(events_pb2.ListMyEventsReq(subscribed=True)) 

1912 assert [event.event_id for event in res.events] == [e1, e5] 

1913 

1914 res = api.ListMyEvents(events_pb2.ListMyEventsReq(attending=True)) 

1915 assert [event.event_id for event in res.events] == [e1, e3, e5] 

1916 

1917 res = api.ListMyEvents(events_pb2.ListMyEventsReq(organizing=True)) 

1918 assert [event.event_id for event in res.events] == [e1, e5] 

1919 

1920 with events_session(token3) as api: 

1921 res = api.ListMyEvents(events_pb2.ListMyEventsReq()) 

1922 assert [event.event_id for event in res.events] == [e1, e2, e3, e4, e5] 

1923 

1924 res = api.ListMyEvents(events_pb2.ListMyEventsReq(subscribed=True)) 

1925 assert [event.event_id for event in res.events] == [e2, e4] 

1926 

1927 res = api.ListMyEvents(events_pb2.ListMyEventsReq(attending=True)) 

1928 assert [event.event_id for event in res.events] == [e4] 

1929 

1930 res = api.ListMyEvents(events_pb2.ListMyEventsReq(organizing=True)) 

1931 assert [event.event_id for event in res.events] == [e3, e4] 

1932 

1933 res = api.ListMyEvents(events_pb2.ListMyEventsReq(my_communities=True)) 

1934 assert [event.event_id for event in res.events] == [e1, e2, e3, e4, e5] 

1935 

1936 with events_session(token5) as api: 

1937 res = api.ListAllEvents(events_pb2.ListAllEventsReq()) 

1938 assert [event.event_id for event in res.events] == [e1, e2, e3, e4, e5, e6] 

1939 

1940 

1941def test_RemoveEventOrganizer(db): 

1942 user1, token1 = generate_user() 

1943 user2, token2 = generate_user() 

1944 

1945 with session_scope() as session: 

1946 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id 

1947 

1948 with events_session(token1) as api: 

1949 event_id = api.CreateEvent( 

1950 events_pb2.CreateEventReq( 

1951 title="Dummy Title", 

1952 content="Dummy content.", 

1953 offline_information=events_pb2.OfflineEventInformation( 

1954 address="Near Null Island", 

1955 lat=0.1, 

1956 lng=0.2, 

1957 ), 

1958 start_time=Timestamp_from_datetime(now() + timedelta(hours=2)), 

1959 end_time=Timestamp_from_datetime(now() + timedelta(hours=5)), 

1960 timezone="UTC", 

1961 ) 

1962 ).event_id 

1963 

1964 with events_session(token2) as api: 

1965 assert not api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).organizer 

1966 

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

1968 api.RemoveEventOrganizer(events_pb2.RemoveEventOrganizerReq(event_id=event_id)) 

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

1970 assert e.value.details() == errors.EVENT_NOT_AN_ORGANIZER 

1971 

1972 assert not api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).organizer 

1973 

1974 with events_session(token1) as api: 

1975 api.InviteEventOrganizer(events_pb2.InviteEventOrganizerReq(event_id=event_id, user_id=user2.id)) 

1976 

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

1978 api.RemoveEventOrganizer(events_pb2.RemoveEventOrganizerReq(event_id=event_id)) 

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

1980 assert e.value.details() == errors.EVENT_CANT_REMOVE_OWNER_AS_ORGANIZER 

1981 

1982 with events_session(token2) as api: 

1983 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

1984 assert res.organizer 

1985 assert res.organizer_count == 2 

1986 api.RemoveEventOrganizer(events_pb2.RemoveEventOrganizerReq(event_id=event_id)) 

1987 assert not api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).organizer 

1988 

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

1990 api.RemoveEventOrganizer(events_pb2.RemoveEventOrganizerReq(event_id=event_id)) 

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

1992 assert e.value.details() == errors.EVENT_NOT_AN_ORGANIZER 

1993 

1994 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id)) 

1995 assert not res.organizer 

1996 assert res.organizer_count == 1 

1997 

1998 

1999def test_ListEventAttendees_regression(db): 

2000 # see issue #1617: 

2001 # 

2002 # 1. Create an event 

2003 # 2. Transfer the event to a community (although this step probably not necessarily, only needed for it to show up in UI/`ListEvents` from `communities.proto` 

2004 # 3. Change the current user's attendance state to "not going" (with `SetEventAttendance`) 

2005 # 4. Change the current user's attendance state to "going" again 

2006 # 

2007 # **Expected behaviour** 

2008 # `ListEventAttendees` should return the current user's ID 

2009 # 

2010 # **Actual/current behaviour** 

2011 # `ListEventAttendees` returns another user's ID. This ID seems to be determined from the row's auto increment ID in `event_occurrence_attendees` in the database 

2012 

2013 user1, token1 = generate_user() 

2014 user2, token2 = generate_user() 

2015 user3, token3 = generate_user() 

2016 user4, token4 = generate_user() 

2017 user5, token5 = generate_user() 

2018 

2019 with session_scope() as session: 

2020 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id 

2021 

2022 start_time = now() + timedelta(hours=2) 

2023 end_time = start_time + timedelta(hours=3) 

2024 

2025 with events_session(token1) as api: 

2026 res = api.CreateEvent( 

2027 events_pb2.CreateEventReq( 

2028 title="Dummy Title", 

2029 content="Dummy content.", 

2030 online_information=events_pb2.OnlineEventInformation( 

2031 link="https://couchers.org", 

2032 ), 

2033 parent_community_id=c_id, 

2034 start_time=Timestamp_from_datetime(start_time), 

2035 end_time=Timestamp_from_datetime(end_time), 

2036 timezone="UTC", 

2037 ) 

2038 ) 

2039 

2040 res = api.TransferEvent( 

2041 events_pb2.TransferEventReq( 

2042 event_id=res.event_id, 

2043 new_owner_community_id=c_id, 

2044 ) 

2045 ) 

2046 

2047 event_id = res.event_id 

2048 

2049 api.SetEventAttendance( 

2050 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_NOT_GOING) 

2051 ) 

2052 api.SetEventAttendance( 

2053 events_pb2.SetEventAttendanceReq(event_id=event_id, attendance_state=events_pb2.ATTENDANCE_STATE_GOING) 

2054 ) 

2055 

2056 res = api.ListEventAttendees(events_pb2.ListEventAttendeesReq(event_id=event_id)) 

2057 assert len(res.attendee_user_ids) == 1 

2058 assert res.attendee_user_ids[0] == user1.id 

2059 

2060 

2061def test_event_threads(db, push_collector): 

2062 user1, token1 = generate_user() 

2063 user2, token2 = generate_user() 

2064 user3, token3 = generate_user() 

2065 user4, token4 = generate_user() 

2066 

2067 with session_scope() as session: 

2068 c = create_community(session, 0, 2, "Community", [user3], [], None) 

2069 h = create_group(session, "Group", [user4], [], c) 

2070 c_id = c.id 

2071 h_id = h.id 

2072 user4_id = user4.id 

2073 

2074 with events_session(token1) as api: 

2075 event = api.CreateEvent( 

2076 events_pb2.CreateEventReq( 

2077 title="Dummy Title", 

2078 content="Dummy content.", 

2079 offline_information=events_pb2.OfflineEventInformation( 

2080 address="Near Null Island", 

2081 lat=0.1, 

2082 lng=0.2, 

2083 ), 

2084 start_time=Timestamp_from_datetime(now() + timedelta(hours=2)), 

2085 end_time=Timestamp_from_datetime(now() + timedelta(hours=5)), 

2086 timezone="UTC", 

2087 ) 

2088 ) 

2089 

2090 with threads_session(token2) as api: 

2091 reply_id = api.PostReply(threads_pb2.PostReplyReq(thread_id=event.thread.thread_id, content="hi")).thread_id 

2092 

2093 with events_session(token3) as api: 

2094 res = api.GetEvent(events_pb2.GetEventReq(event_id=event.event_id)) 

2095 assert res.thread.num_responses == 1 

2096 

2097 with threads_session(token3) as api: 

2098 ret = api.GetThread(threads_pb2.GetThreadReq(thread_id=res.thread.thread_id)) 

2099 assert len(ret.replies) == 1 

2100 assert not ret.next_page_token 

2101 assert ret.replies[0].thread_id == reply_id 

2102 assert ret.replies[0].content == "hi" 

2103 assert ret.replies[0].author_user_id == user2.id 

2104 assert ret.replies[0].num_replies == 0 

2105 

2106 api.PostReply(threads_pb2.PostReplyReq(thread_id=reply_id, content="what a silly comment")) 

2107 

2108 process_jobs() 

2109 

2110 push_collector.assert_user_has_single_matching(user1.id, title=f'{user2.name} commented on "Dummy Title"') 

2111 push_collector.assert_user_has_single_matching(user2.id, title="Dummy Title") 

2112 push_collector.assert_user_has_count(user4_id, 0) 

2113 

2114 

2115def test_can_overlap_other_events_schedule_regression(db): 

2116 # we had a bug where we were checking overlapping for *all* occurrences of *all* events, not just the ones for this event 

2117 user, token = generate_user() 

2118 

2119 with session_scope() as session: 

2120 c_id = create_community(session, 0, 2, "Community", [user], [], None).id 

2121 

2122 start = now() 

2123 

2124 with events_session(token) as api: 

2125 # create another event, should be able to overlap with this one 

2126 api.CreateEvent( 

2127 events_pb2.CreateEventReq( 

2128 title="Dummy Title", 

2129 content="Dummy content.", 

2130 parent_community_id=c_id, 

2131 online_information=events_pb2.OnlineEventInformation( 

2132 link="https://couchers.org/meet/", 

2133 ), 

2134 start_time=Timestamp_from_datetime(start + timedelta(hours=1)), 

2135 end_time=Timestamp_from_datetime(start + timedelta(hours=5)), 

2136 timezone="UTC", 

2137 ) 

2138 ) 

2139 

2140 # this event 

2141 res = api.CreateEvent( 

2142 events_pb2.CreateEventReq( 

2143 title="Dummy Title", 

2144 content="Dummy content.", 

2145 parent_community_id=c_id, 

2146 online_information=events_pb2.OnlineEventInformation( 

2147 link="https://couchers.org/meet/", 

2148 ), 

2149 start_time=Timestamp_from_datetime(start + timedelta(hours=1)), 

2150 end_time=Timestamp_from_datetime(start + timedelta(hours=2)), 

2151 timezone="UTC", 

2152 ) 

2153 ) 

2154 

2155 # this doesn't overlap with the just created event, but does overlap with the occurrence from earlier; which should be no problem 

2156 api.ScheduleEvent( 

2157 events_pb2.ScheduleEventReq( 

2158 event_id=res.event_id, 

2159 content="New event occurrence", 

2160 offline_information=events_pb2.OfflineEventInformation( 

2161 address="A bit further but still near Null Island", 

2162 lat=0.3, 

2163 lng=0.2, 

2164 ), 

2165 start_time=Timestamp_from_datetime(start + timedelta(hours=3)), 

2166 end_time=Timestamp_from_datetime(start + timedelta(hours=6)), 

2167 timezone="UTC", 

2168 ) 

2169 ) 

2170 

2171 

2172def test_can_overlap_other_events_update_regression(db): 

2173 user, token = generate_user() 

2174 

2175 with session_scope() as session: 

2176 c_id = create_community(session, 0, 2, "Community", [user], [], None).id 

2177 

2178 start = now() 

2179 

2180 with events_session(token) as api: 

2181 # create another event, should be able to overlap with this one 

2182 api.CreateEvent( 

2183 events_pb2.CreateEventReq( 

2184 title="Dummy Title", 

2185 content="Dummy content.", 

2186 parent_community_id=c_id, 

2187 online_information=events_pb2.OnlineEventInformation( 

2188 link="https://couchers.org/meet/", 

2189 ), 

2190 start_time=Timestamp_from_datetime(start + timedelta(hours=1)), 

2191 end_time=Timestamp_from_datetime(start + timedelta(hours=3)), 

2192 timezone="UTC", 

2193 ) 

2194 ) 

2195 

2196 res = api.CreateEvent( 

2197 events_pb2.CreateEventReq( 

2198 title="Dummy Title", 

2199 content="Dummy content.", 

2200 parent_community_id=c_id, 

2201 online_information=events_pb2.OnlineEventInformation( 

2202 link="https://couchers.org/meet/", 

2203 ), 

2204 start_time=Timestamp_from_datetime(start + timedelta(hours=7)), 

2205 end_time=Timestamp_from_datetime(start + timedelta(hours=8)), 

2206 timezone="UTC", 

2207 ) 

2208 ) 

2209 

2210 event_id = api.ScheduleEvent( 

2211 events_pb2.ScheduleEventReq( 

2212 event_id=res.event_id, 

2213 content="New event occurrence", 

2214 offline_information=events_pb2.OfflineEventInformation( 

2215 address="A bit further but still near Null Island", 

2216 lat=0.3, 

2217 lng=0.2, 

2218 ), 

2219 start_time=Timestamp_from_datetime(start + timedelta(hours=4)), 

2220 end_time=Timestamp_from_datetime(start + timedelta(hours=6)), 

2221 timezone="UTC", 

2222 ) 

2223 ).event_id 

2224 

2225 # can overlap with this current existing occurrence 

2226 api.UpdateEvent( 

2227 events_pb2.UpdateEventReq( 

2228 event_id=event_id, 

2229 start_time=Timestamp_from_datetime(start + timedelta(hours=5)), 

2230 end_time=Timestamp_from_datetime(start + timedelta(hours=6)), 

2231 ) 

2232 ) 

2233 

2234 api.UpdateEvent( 

2235 events_pb2.UpdateEventReq( 

2236 event_id=event_id, 

2237 start_time=Timestamp_from_datetime(start + timedelta(hours=2)), 

2238 end_time=Timestamp_from_datetime(start + timedelta(hours=4)), 

2239 ) 

2240 ) 

2241 

2242 

2243def test_list_past_events_regression(db): 

2244 # test for a bug where listing past events didn't work if they didn't have a future occurrence 

2245 user, token = generate_user() 

2246 

2247 with session_scope() as session: 

2248 c_id = create_community(session, 0, 2, "Community", [user], [], None).id 

2249 

2250 start = now() 

2251 

2252 with events_session(token) as api: 

2253 api.CreateEvent( 

2254 events_pb2.CreateEventReq( 

2255 title="Dummy Title", 

2256 content="Dummy content.", 

2257 parent_community_id=c_id, 

2258 online_information=events_pb2.OnlineEventInformation( 

2259 link="https://couchers.org/meet/", 

2260 ), 

2261 start_time=Timestamp_from_datetime(start + timedelta(hours=3)), 

2262 end_time=Timestamp_from_datetime(start + timedelta(hours=4)), 

2263 timezone="UTC", 

2264 ) 

2265 ) 

2266 

2267 with session_scope() as session: 

2268 session.execute( 

2269 update(EventOccurrence).values( 

2270 during=DateTimeTZRange(start + timedelta(hours=-5), start + timedelta(hours=-4)) 

2271 ) 

2272 ) 

2273 

2274 with events_session(token) as api: 

2275 res = api.ListAllEvents(events_pb2.ListAllEventsReq(past=True)) 

2276 assert len(res.events) == 1 

2277 

2278 

2279def test_community_invite_requests(db): 

2280 user1, token1 = generate_user(complete_profile=True) 

2281 user2, token2 = generate_user() 

2282 user3, token3 = generate_user() 

2283 user4, token4 = generate_user() 

2284 user5, token5 = generate_user(is_superuser=True) 

2285 

2286 with session_scope() as session: 

2287 w = create_community(session, 0, 2, "World Community", [user5], [], None) 

2288 c_id = create_community(session, 0, 2, "Community", [user1, user3, user4], [], w).id 

2289 

2290 enforce_community_memberships() 

2291 

2292 with events_session(token1) as api: 

2293 res = api.CreateEvent( 

2294 events_pb2.CreateEventReq( 

2295 title="Dummy Title", 

2296 content="Dummy content.", 

2297 parent_community_id=c_id, 

2298 online_information=events_pb2.OnlineEventInformation( 

2299 link="https://couchers.org/meet/", 

2300 ), 

2301 start_time=Timestamp_from_datetime(now() + timedelta(hours=3)), 

2302 end_time=Timestamp_from_datetime(now() + timedelta(hours=4)), 

2303 timezone="UTC", 

2304 ) 

2305 ) 

2306 user_url = f"http://localhost:3000/user/{user1.username}" 

2307 event_url = f"http://localhost:3000/event/{res.event_id}/{res.slug}" 

2308 

2309 event_id = res.event_id 

2310 

2311 with mock_notification_email() as mock: 

2312 api.RequestCommunityInvite(events_pb2.RequestCommunityInviteReq(event_id=event_id)) 

2313 assert mock.call_count == 1 

2314 e = email_fields(mock) 

2315 assert e.recipient == "mods@couchers.org.invalid" 

2316 

2317 assert user_url in e.plain 

2318 assert event_url in e.plain 

2319 

2320 # can't send another req 

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

2322 api.RequestCommunityInvite(events_pb2.RequestCommunityInviteReq(event_id=event_id)) 

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

2324 assert e.value.details() == errors.EVENT_COMMUNITY_INVITE_ALREADY_REQUESTED 

2325 

2326 # another user can send one though 

2327 with events_session(token3) as api: 

2328 api.RequestCommunityInvite(events_pb2.RequestCommunityInviteReq(event_id=event_id)) 

2329 

2330 # but not a non-admin 

2331 with events_session(token2) as api: 

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

2333 api.RequestCommunityInvite(events_pb2.RequestCommunityInviteReq(event_id=event_id)) 

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

2335 assert e.value.details() == errors.EVENT_EDIT_PERMISSION_DENIED 

2336 

2337 with real_admin_session(token5) as admin: 

2338 res = admin.ListEventCommunityInviteRequests(admin_pb2.ListEventCommunityInviteRequestsReq()) 

2339 assert len(res.requests) == 2 

2340 assert res.requests[0].user_id == user1.id 

2341 assert res.requests[0].approx_users_to_notify == 3 

2342 assert res.requests[1].user_id == user3.id 

2343 assert res.requests[1].approx_users_to_notify == 3 

2344 

2345 admin.DecideEventCommunityInviteRequest( 

2346 admin_pb2.DecideEventCommunityInviteRequestReq( 

2347 event_community_invite_request_id=res.requests[0].event_community_invite_request_id, 

2348 approve=False, 

2349 ) 

2350 ) 

2351 

2352 admin.DecideEventCommunityInviteRequest( 

2353 admin_pb2.DecideEventCommunityInviteRequestReq( 

2354 event_community_invite_request_id=res.requests[1].event_community_invite_request_id, 

2355 approve=True, 

2356 ) 

2357 ) 

2358 

2359 # not after approve 

2360 with events_session(token4) as api: 

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

2362 api.RequestCommunityInvite(events_pb2.RequestCommunityInviteReq(event_id=event_id)) 

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

2364 assert e.value.details() == errors.EVENT_COMMUNITY_INVITE_ALREADY_APPROVED