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

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1032 statements  

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.utils import Timestamp_from_datetime, now, to_aware_datetime 

13from proto import events_pb2, threads_pb2 

14from tests.test_communities import create_community, create_group 

15from tests.test_fixtures import db, events_session, generate_user, testconfig, threads_session # noqa 

16 

17 

18@pytest.fixture(autouse=True) 

19def _(testconfig): 

20 pass 

21 

22 

23def test_CreateEvent(db): 

24 # test cases: 

25 # can create event 

26 # cannot create event with missing details 

27 # can create online event 

28 # can create in person event 

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

30 # can create in different timezones 

31 

32 # event creator 

33 user1, token1 = generate_user() 

34 # community moderator 

35 user2, token2 = generate_user() 

36 # third party 

37 user3, token3 = generate_user() 

38 

39 with session_scope() as session: 

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

41 

42 time_before = now() 

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

44 end_time = start_time + timedelta(hours=3) 

45 

46 with events_session(token1) as api: 

47 # in person event 

48 res = api.CreateEvent( 

49 events_pb2.CreateEventReq( 

50 title="Dummy Title", 

51 content="Dummy content.", 

52 photo_key=None, 

53 offline_information=events_pb2.OfflineEventInformation( 

54 address="Near Null Island", 

55 lat=0.1, 

56 lng=0.2, 

57 ), 

58 start_time=Timestamp_from_datetime(start_time), 

59 end_time=Timestamp_from_datetime(end_time), 

60 timezone="UTC", 

61 ) 

62 ) 

63 

64 assert res.is_next 

65 assert res.title == "Dummy Title" 

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

67 assert res.content == "Dummy content." 

68 assert not res.photo_url 

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

70 assert res.offline_information.lat == 0.1 

71 assert res.offline_information.lng == 0.2 

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

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

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

75 assert res.creator_user_id == user1.id 

76 assert to_aware_datetime(res.start_time) == start_time 

77 assert to_aware_datetime(res.end_time) == end_time 

78 # assert res.timezone == "UTC" 

79 assert res.start_time_display 

80 assert res.end_time_display 

81 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_GOING 

82 assert res.organizer 

83 assert res.subscriber 

84 assert res.going_count == 1 

85 assert res.maybe_count == 0 

86 assert res.organizer_count == 1 

87 assert res.subscriber_count == 1 

88 assert res.owner_user_id == user1.id 

89 assert not res.owner_community_id 

90 assert not res.owner_group_id 

91 assert res.thread.thread_id 

92 assert res.can_edit 

93 assert not res.can_moderate 

94 

95 event_id = res.event_id 

96 

97 with events_session(token2) as api: 

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

99 

100 assert res.is_next 

101 assert res.title == "Dummy Title" 

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

103 assert res.content == "Dummy content." 

104 assert not res.photo_url 

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

106 assert res.offline_information.lat == 0.1 

107 assert res.offline_information.lng == 0.2 

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

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

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

111 assert res.creator_user_id == user1.id 

112 assert to_aware_datetime(res.start_time) == start_time 

113 assert to_aware_datetime(res.end_time) == end_time 

114 # assert res.timezone == "UTC" 

115 assert res.start_time_display 

116 assert res.end_time_display 

117 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

118 assert not res.organizer 

119 assert not res.subscriber 

120 assert res.going_count == 1 

121 assert res.maybe_count == 0 

122 assert res.organizer_count == 1 

123 assert res.subscriber_count == 1 

124 assert res.owner_user_id == user1.id 

125 assert not res.owner_community_id 

126 assert not res.owner_group_id 

127 assert res.thread.thread_id 

128 assert not res.can_edit 

129 assert res.can_moderate 

130 

131 with events_session(token3) as api: 

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

133 

134 assert res.is_next 

135 assert res.title == "Dummy Title" 

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

137 assert res.content == "Dummy content." 

138 assert not res.photo_url 

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

140 assert res.offline_information.lat == 0.1 

141 assert res.offline_information.lng == 0.2 

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

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

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

145 assert res.creator_user_id == user1.id 

146 assert to_aware_datetime(res.start_time) == start_time 

147 assert to_aware_datetime(res.end_time) == end_time 

148 # assert res.timezone == "UTC" 

149 assert res.start_time_display 

150 assert res.end_time_display 

151 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

152 assert not res.organizer 

153 assert not res.subscriber 

154 assert res.going_count == 1 

155 assert res.maybe_count == 0 

156 assert res.organizer_count == 1 

157 assert res.subscriber_count == 1 

158 assert res.owner_user_id == user1.id 

159 assert not res.owner_community_id 

160 assert not res.owner_group_id 

161 assert res.thread.thread_id 

162 assert not res.can_edit 

163 assert not res.can_moderate 

164 

165 with events_session(token1) as api: 

166 # online only event 

167 res = api.CreateEvent( 

168 events_pb2.CreateEventReq( 

169 title="Dummy Title", 

170 content="Dummy content.", 

171 photo_key=None, 

172 online_information=events_pb2.OnlineEventInformation( 

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

174 ), 

175 parent_community_id=c_id, 

176 start_time=Timestamp_from_datetime(start_time), 

177 end_time=Timestamp_from_datetime(end_time), 

178 timezone="UTC", 

179 ) 

180 ) 

181 

182 assert res.is_next 

183 assert res.title == "Dummy Title" 

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

185 assert res.content == "Dummy content." 

186 assert not res.photo_url 

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

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

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

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

191 assert res.creator_user_id == user1.id 

192 assert to_aware_datetime(res.start_time) == start_time 

193 assert to_aware_datetime(res.end_time) == end_time 

194 # assert res.timezone == "UTC" 

195 assert res.start_time_display 

196 assert res.end_time_display 

197 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_GOING 

198 assert res.organizer 

199 assert res.subscriber 

200 assert res.going_count == 1 

201 assert res.maybe_count == 0 

202 assert res.organizer_count == 1 

203 assert res.subscriber_count == 1 

204 assert res.owner_user_id == user1.id 

205 assert not res.owner_community_id 

206 assert not res.owner_group_id 

207 assert res.thread.thread_id 

208 assert res.can_edit 

209 assert not res.can_moderate 

210 

211 event_id = res.event_id 

212 

213 with events_session(token2) as api: 

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

215 

216 assert res.is_next 

217 assert res.title == "Dummy Title" 

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

219 assert res.content == "Dummy content." 

220 assert not res.photo_url 

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

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

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

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

225 assert res.creator_user_id == user1.id 

226 assert to_aware_datetime(res.start_time) == start_time 

227 assert to_aware_datetime(res.end_time) == end_time 

228 # assert res.timezone == "UTC" 

229 assert res.start_time_display 

230 assert res.end_time_display 

231 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

232 assert not res.organizer 

233 assert not res.subscriber 

234 assert res.going_count == 1 

235 assert res.maybe_count == 0 

236 assert res.organizer_count == 1 

237 assert res.subscriber_count == 1 

238 assert res.owner_user_id == user1.id 

239 assert not res.owner_community_id 

240 assert not res.owner_group_id 

241 assert res.thread.thread_id 

242 assert not res.can_edit 

243 assert res.can_moderate 

244 

245 with events_session(token3) as api: 

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

247 

248 assert res.is_next 

249 assert res.title == "Dummy Title" 

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

251 assert res.content == "Dummy content." 

252 assert not res.photo_url 

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

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

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

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

257 assert res.creator_user_id == user1.id 

258 assert to_aware_datetime(res.start_time) == start_time 

259 assert to_aware_datetime(res.end_time) == end_time 

260 # assert res.timezone == "UTC" 

261 assert res.start_time_display 

262 assert res.end_time_display 

263 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

264 assert not res.organizer 

265 assert not res.subscriber 

266 assert res.going_count == 1 

267 assert res.maybe_count == 0 

268 assert res.organizer_count == 1 

269 assert res.subscriber_count == 1 

270 assert res.owner_user_id == user1.id 

271 assert not res.owner_community_id 

272 assert not res.owner_group_id 

273 assert res.thread.thread_id 

274 assert not res.can_edit 

275 assert not res.can_moderate 

276 

277 with events_session(token1) as api: 

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

279 api.CreateEvent( 

280 events_pb2.CreateEventReq( 

281 title="Dummy Title", 

282 content="Dummy content.", 

283 photo_key=None, 

284 online_information=events_pb2.OnlineEventInformation( 

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

286 ), 

287 start_time=Timestamp_from_datetime(start_time), 

288 end_time=Timestamp_from_datetime(end_time), 

289 timezone="UTC", 

290 ) 

291 ) 

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

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

294 

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

296 api.CreateEvent( 

297 events_pb2.CreateEventReq( 

298 # title="Dummy Title", 

299 content="Dummy content.", 

300 photo_key=None, 

301 offline_information=events_pb2.OfflineEventInformation( 

302 address="Near Null Island", 

303 lat=0.1, 

304 lng=0.1, 

305 ), 

306 start_time=Timestamp_from_datetime(start_time), 

307 end_time=Timestamp_from_datetime(end_time), 

308 timezone="UTC", 

309 ) 

310 ) 

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

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

313 

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

315 api.CreateEvent( 

316 events_pb2.CreateEventReq( 

317 title="Dummy Title", 

318 # content="Dummy content.", 

319 photo_key=None, 

320 offline_information=events_pb2.OfflineEventInformation( 

321 address="Near Null Island", 

322 lat=0.1, 

323 lng=0.1, 

324 ), 

325 start_time=Timestamp_from_datetime(start_time), 

326 end_time=Timestamp_from_datetime(end_time), 

327 timezone="UTC", 

328 ) 

329 ) 

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

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

332 

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

334 api.CreateEvent( 

335 events_pb2.CreateEventReq( 

336 title="Dummy Title", 

337 content="Dummy content.", 

338 photo_key="nonexistent", 

339 offline_information=events_pb2.OfflineEventInformation( 

340 address="Near Null Island", 

341 lat=0.1, 

342 lng=0.1, 

343 ), 

344 start_time=Timestamp_from_datetime(start_time), 

345 end_time=Timestamp_from_datetime(end_time), 

346 timezone="UTC", 

347 ) 

348 ) 

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

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

351 

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

353 api.CreateEvent( 

354 events_pb2.CreateEventReq( 

355 title="Dummy Title", 

356 content="Dummy content.", 

357 photo_key=None, 

358 offline_information=events_pb2.OfflineEventInformation( 

359 address="Near Null Island", 

360 ), 

361 start_time=Timestamp_from_datetime(start_time), 

362 end_time=Timestamp_from_datetime(end_time), 

363 timezone="UTC", 

364 ) 

365 ) 

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

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

368 

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

370 api.CreateEvent( 

371 events_pb2.CreateEventReq( 

372 title="Dummy Title", 

373 content="Dummy content.", 

374 photo_key=None, 

375 offline_information=events_pb2.OfflineEventInformation( 

376 lat=0.1, 

377 lng=0.1, 

378 ), 

379 start_time=Timestamp_from_datetime(start_time), 

380 end_time=Timestamp_from_datetime(end_time), 

381 timezone="UTC", 

382 ) 

383 ) 

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

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

386 

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

388 api.CreateEvent( 

389 events_pb2.CreateEventReq( 

390 title="Dummy Title", 

391 content="Dummy content.", 

392 photo_key=None, 

393 online_information=events_pb2.OnlineEventInformation(), 

394 start_time=Timestamp_from_datetime(start_time), 

395 end_time=Timestamp_from_datetime(end_time), 

396 timezone="UTC", 

397 ) 

398 ) 

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

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

401 

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

403 api.CreateEvent( 

404 events_pb2.CreateEventReq( 

405 title="Dummy Title", 

406 content="Dummy content.", 

407 parent_community_id=c_id, 

408 online_information=events_pb2.OnlineEventInformation( 

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

410 ), 

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

412 end_time=Timestamp_from_datetime(end_time), 

413 timezone="UTC", 

414 ) 

415 ) 

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

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

418 

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

420 api.CreateEvent( 

421 events_pb2.CreateEventReq( 

422 title="Dummy Title", 

423 content="Dummy content.", 

424 parent_community_id=c_id, 

425 online_information=events_pb2.OnlineEventInformation( 

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

427 ), 

428 start_time=Timestamp_from_datetime(end_time), 

429 end_time=Timestamp_from_datetime(start_time), 

430 timezone="UTC", 

431 ) 

432 ) 

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

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

435 

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

437 api.CreateEvent( 

438 events_pb2.CreateEventReq( 

439 title="Dummy Title", 

440 content="Dummy content.", 

441 parent_community_id=c_id, 

442 online_information=events_pb2.OnlineEventInformation( 

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

444 ), 

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

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

447 timezone="UTC", 

448 ) 

449 ) 

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

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

452 

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

454 api.CreateEvent( 

455 events_pb2.CreateEventReq( 

456 title="Dummy Title", 

457 content="Dummy content.", 

458 parent_community_id=c_id, 

459 online_information=events_pb2.OnlineEventInformation( 

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

461 ), 

462 start_time=Timestamp_from_datetime(start_time), 

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

464 timezone="UTC", 

465 ) 

466 ) 

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

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

469 

470 

471def test_ScheduleEvent(db): 

472 # test cases: 

473 # can schedule a new event occurrence 

474 

475 user, token = generate_user() 

476 

477 with session_scope() as session: 

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

479 

480 time_before = now() 

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

482 end_time = start_time + timedelta(hours=3) 

483 

484 with events_session(token) as api: 

485 res = api.CreateEvent( 

486 events_pb2.CreateEventReq( 

487 title="Dummy Title", 

488 content="Dummy content.", 

489 parent_community_id=c_id, 

490 online_information=events_pb2.OnlineEventInformation( 

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

492 ), 

493 start_time=Timestamp_from_datetime(start_time), 

494 end_time=Timestamp_from_datetime(end_time), 

495 timezone="UTC", 

496 ) 

497 ) 

498 

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

500 new_end_time = new_start_time + timedelta(hours=2) 

501 

502 res = api.ScheduleEvent( 

503 events_pb2.ScheduleEventReq( 

504 event_id=res.event_id, 

505 content="New event occurrence", 

506 offline_information=events_pb2.OfflineEventInformation( 

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

508 lat=0.3, 

509 lng=0.2, 

510 ), 

511 start_time=Timestamp_from_datetime(new_start_time), 

512 end_time=Timestamp_from_datetime(new_end_time), 

513 timezone="UTC", 

514 ) 

515 ) 

516 

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

518 

519 assert not res.is_next 

520 assert res.title == "Dummy Title" 

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

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

523 assert not res.photo_url 

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

525 assert res.offline_information.lat == 0.3 

526 assert res.offline_information.lng == 0.2 

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

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

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

530 assert res.creator_user_id == user.id 

531 assert to_aware_datetime(res.start_time) == new_start_time 

532 assert to_aware_datetime(res.end_time) == new_end_time 

533 # assert res.timezone == "UTC" 

534 assert res.start_time_display 

535 assert res.end_time_display 

536 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_GOING 

537 assert res.organizer 

538 assert res.subscriber 

539 assert res.going_count == 1 

540 assert res.maybe_count == 0 

541 assert res.organizer_count == 1 

542 assert res.subscriber_count == 1 

543 assert res.owner_user_id == user.id 

544 assert not res.owner_community_id 

545 assert not res.owner_group_id 

546 assert res.thread.thread_id 

547 assert res.can_edit 

548 assert res.can_moderate 

549 

550 

551def test_cannot_overlap_occurrences_schedule(db): 

552 user, token = generate_user() 

553 

554 with session_scope() as session: 

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

556 

557 start = now() 

558 

559 with events_session(token) as api: 

560 res = api.CreateEvent( 

561 events_pb2.CreateEventReq( 

562 title="Dummy Title", 

563 content="Dummy content.", 

564 parent_community_id=c_id, 

565 online_information=events_pb2.OnlineEventInformation( 

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

567 ), 

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

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

570 timezone="UTC", 

571 ) 

572 ) 

573 

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

575 api.ScheduleEvent( 

576 events_pb2.ScheduleEventReq( 

577 event_id=res.event_id, 

578 content="New event occurrence", 

579 offline_information=events_pb2.OfflineEventInformation( 

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

581 lat=0.3, 

582 lng=0.2, 

583 ), 

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

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

586 timezone="UTC", 

587 ) 

588 ) 

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

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

591 

592 

593def test_cannot_overlap_occurrences_update(db): 

594 user, token = generate_user() 

595 

596 with session_scope() as session: 

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

598 

599 start = now() 

600 

601 with events_session(token) as api: 

602 res = api.CreateEvent( 

603 events_pb2.CreateEventReq( 

604 title="Dummy Title", 

605 content="Dummy content.", 

606 parent_community_id=c_id, 

607 online_information=events_pb2.OnlineEventInformation( 

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

609 ), 

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

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

612 timezone="UTC", 

613 ) 

614 ) 

615 

616 event_id = api.ScheduleEvent( 

617 events_pb2.ScheduleEventReq( 

618 event_id=res.event_id, 

619 content="New event occurrence", 

620 offline_information=events_pb2.OfflineEventInformation( 

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

622 lat=0.3, 

623 lng=0.2, 

624 ), 

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

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

627 timezone="UTC", 

628 ) 

629 ).event_id 

630 

631 # can overlap with this current existing occurrence 

632 api.UpdateEvent( 

633 events_pb2.UpdateEventReq( 

634 event_id=event_id, 

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

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

637 ) 

638 ) 

639 

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

641 api.UpdateEvent( 

642 events_pb2.UpdateEventReq( 

643 event_id=event_id, 

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

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

646 ) 

647 ) 

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

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

650 

651 

652def test_UpdateEvent_single(db): 

653 # test cases: 

654 # owner can update 

655 # community owner can update 

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

657 # notifies attendees 

658 

659 # event creator 

660 user1, token1 = generate_user() 

661 # community moderator 

662 user2, token2 = generate_user() 

663 # third parties 

664 user3, token3 = generate_user() 

665 user4, token4 = generate_user() 

666 user5, token5 = generate_user() 

667 user6, token6 = generate_user() 

668 

669 with session_scope() as session: 

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

671 

672 time_before = now() 

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

674 end_time = start_time + timedelta(hours=3) 

675 

676 with events_session(token1) as api: 

677 res = api.CreateEvent( 

678 events_pb2.CreateEventReq( 

679 title="Dummy Title", 

680 content="Dummy content.", 

681 offline_information=events_pb2.OfflineEventInformation( 

682 address="Near Null Island", 

683 lat=0.1, 

684 lng=0.2, 

685 ), 

686 start_time=Timestamp_from_datetime(start_time), 

687 end_time=Timestamp_from_datetime(end_time), 

688 timezone="UTC", 

689 ) 

690 ) 

691 

692 event_id = res.event_id 

693 

694 with events_session(token4) as api: 

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

696 

697 with events_session(token5) as api: 

698 api.SetEventAttendance( 

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

700 ) 

701 

702 with events_session(token6) as api: 

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

704 api.SetEventAttendance( 

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

706 ) 

707 

708 time_before_update = now() 

709 

710 with events_session(token1) as api: 

711 res = api.UpdateEvent( 

712 events_pb2.UpdateEventReq( 

713 event_id=event_id, 

714 ) 

715 ) 

716 

717 with events_session(token1) as api: 

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

719 

720 assert res.is_next 

721 assert res.title == "Dummy Title" 

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

723 assert res.content == "Dummy content." 

724 assert not res.photo_url 

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

726 assert res.offline_information.lat == 0.1 

727 assert res.offline_information.lng == 0.2 

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

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

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

731 assert res.creator_user_id == user1.id 

732 assert to_aware_datetime(res.start_time) == start_time 

733 assert to_aware_datetime(res.end_time) == end_time 

734 # assert res.timezone == "UTC" 

735 assert res.start_time_display 

736 assert res.end_time_display 

737 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_GOING 

738 assert res.organizer 

739 assert res.subscriber 

740 assert res.going_count == 2 

741 assert res.maybe_count == 1 

742 assert res.organizer_count == 1 

743 assert res.subscriber_count == 3 

744 assert res.owner_user_id == user1.id 

745 assert not res.owner_community_id 

746 assert not res.owner_group_id 

747 assert res.thread.thread_id 

748 assert res.can_edit 

749 assert not res.can_moderate 

750 

751 with events_session(token2) as api: 

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

753 

754 assert res.is_next 

755 assert res.title == "Dummy Title" 

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

757 assert res.content == "Dummy content." 

758 assert not res.photo_url 

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

760 assert res.offline_information.lat == 0.1 

761 assert res.offline_information.lng == 0.2 

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

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

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

765 assert res.creator_user_id == user1.id 

766 assert to_aware_datetime(res.start_time) == start_time 

767 assert to_aware_datetime(res.end_time) == end_time 

768 # assert res.timezone == "UTC" 

769 assert res.start_time_display 

770 assert res.end_time_display 

771 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

772 assert not res.organizer 

773 assert not res.subscriber 

774 assert res.going_count == 2 

775 assert res.maybe_count == 1 

776 assert res.organizer_count == 1 

777 assert res.subscriber_count == 3 

778 assert res.owner_user_id == user1.id 

779 assert not res.owner_community_id 

780 assert not res.owner_group_id 

781 assert res.thread.thread_id 

782 assert not res.can_edit 

783 assert res.can_moderate 

784 

785 with events_session(token3) as api: 

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

787 

788 assert res.is_next 

789 assert res.title == "Dummy Title" 

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

791 assert res.content == "Dummy content." 

792 assert not res.photo_url 

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

794 assert res.offline_information.lat == 0.1 

795 assert res.offline_information.lng == 0.2 

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

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

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

799 assert res.creator_user_id == user1.id 

800 assert to_aware_datetime(res.start_time) == start_time 

801 assert to_aware_datetime(res.end_time) == end_time 

802 # assert res.timezone == "UTC" 

803 assert res.start_time_display 

804 assert res.end_time_display 

805 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

806 assert not res.organizer 

807 assert not res.subscriber 

808 assert res.going_count == 2 

809 assert res.maybe_count == 1 

810 assert res.organizer_count == 1 

811 assert res.subscriber_count == 3 

812 assert res.owner_user_id == user1.id 

813 assert not res.owner_community_id 

814 assert not res.owner_group_id 

815 assert res.thread.thread_id 

816 assert not res.can_edit 

817 assert not res.can_moderate 

818 

819 with events_session(token1) as api: 

820 res = api.UpdateEvent( 

821 events_pb2.UpdateEventReq( 

822 event_id=event_id, 

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

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

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

826 start_time=Timestamp_from_datetime(start_time), 

827 end_time=Timestamp_from_datetime(end_time), 

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

829 ) 

830 ) 

831 

832 assert res.is_next 

833 assert res.title == "Dummy Title" 

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

835 assert res.content == "Dummy content." 

836 assert not res.photo_url 

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

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

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

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

841 assert res.creator_user_id == user1.id 

842 assert to_aware_datetime(res.start_time) == start_time 

843 assert to_aware_datetime(res.end_time) == end_time 

844 # assert res.timezone == "UTC" 

845 assert res.start_time_display 

846 assert res.end_time_display 

847 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_GOING 

848 assert res.organizer 

849 assert res.subscriber 

850 assert res.going_count == 2 

851 assert res.maybe_count == 1 

852 assert res.organizer_count == 1 

853 assert res.subscriber_count == 3 

854 assert res.owner_user_id == user1.id 

855 assert not res.owner_community_id 

856 assert not res.owner_group_id 

857 assert res.thread.thread_id 

858 assert res.can_edit 

859 assert not res.can_moderate 

860 

861 event_id = res.event_id 

862 

863 with events_session(token2) as api: 

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

865 

866 assert res.is_next 

867 assert res.title == "Dummy Title" 

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

869 assert res.content == "Dummy content." 

870 assert not res.photo_url 

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

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

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

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

875 assert res.creator_user_id == user1.id 

876 assert to_aware_datetime(res.start_time) == start_time 

877 assert to_aware_datetime(res.end_time) == end_time 

878 # assert res.timezone == "UTC" 

879 assert res.start_time_display 

880 assert res.end_time_display 

881 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

882 assert not res.organizer 

883 assert not res.subscriber 

884 assert res.going_count == 2 

885 assert res.maybe_count == 1 

886 assert res.organizer_count == 1 

887 assert res.subscriber_count == 3 

888 assert res.owner_user_id == user1.id 

889 assert not res.owner_community_id 

890 assert not res.owner_group_id 

891 assert res.thread.thread_id 

892 assert not res.can_edit 

893 assert res.can_moderate 

894 

895 with events_session(token3) as api: 

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

897 

898 assert res.is_next 

899 assert res.title == "Dummy Title" 

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

901 assert res.content == "Dummy content." 

902 assert not res.photo_url 

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

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

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

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

907 assert res.creator_user_id == user1.id 

908 assert to_aware_datetime(res.start_time) == start_time 

909 assert to_aware_datetime(res.end_time) == end_time 

910 # assert res.timezone == "UTC" 

911 assert res.start_time_display 

912 assert res.end_time_display 

913 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

914 assert not res.organizer 

915 assert not res.subscriber 

916 assert res.going_count == 2 

917 assert res.maybe_count == 1 

918 assert res.organizer_count == 1 

919 assert res.subscriber_count == 3 

920 assert res.owner_user_id == user1.id 

921 assert not res.owner_community_id 

922 assert not res.owner_group_id 

923 assert res.thread.thread_id 

924 assert not res.can_edit 

925 assert not res.can_moderate 

926 

927 with events_session(token1) as api: 

928 res = api.UpdateEvent( 

929 events_pb2.UpdateEventReq( 

930 event_id=event_id, 

931 offline_information=events_pb2.OfflineEventInformation( 

932 address="Near Null Island", 

933 lat=0.1, 

934 lng=0.2, 

935 ), 

936 ) 

937 ) 

938 

939 with events_session(token3) as api: 

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

941 

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

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

944 assert res.offline_information.lat == 0.1 

945 assert res.offline_information.lng == 0.2 

946 

947 

948def test_UpdateEvent_all(db): 

949 # event creator 

950 user1, token1 = generate_user() 

951 # community moderator 

952 user2, token2 = generate_user() 

953 # third parties 

954 user3, token3 = generate_user() 

955 user4, token4 = generate_user() 

956 user5, token5 = generate_user() 

957 user6, token6 = generate_user() 

958 

959 with session_scope() as session: 

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

961 

962 time_before = now() 

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

964 end_time = start_time + timedelta(hours=1.5) 

965 

966 event_ids = [] 

967 

968 with events_session(token1) as api: 

969 res = api.CreateEvent( 

970 events_pb2.CreateEventReq( 

971 title="Dummy Title", 

972 content="0th occurrence", 

973 offline_information=events_pb2.OfflineEventInformation( 

974 address="Near Null Island", 

975 lat=0.1, 

976 lng=0.2, 

977 ), 

978 start_time=Timestamp_from_datetime(start_time), 

979 end_time=Timestamp_from_datetime(end_time), 

980 timezone="UTC", 

981 ) 

982 ) 

983 

984 event_id = res.event_id 

985 event_ids.append(event_id) 

986 

987 with events_session(token4) as api: 

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

989 

990 with events_session(token5) as api: 

991 api.SetEventAttendance( 

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

993 ) 

994 

995 with events_session(token6) as api: 

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

997 api.SetEventAttendance( 

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

999 ) 

1000 

1001 with events_session(token1) as api: 

1002 for i in range(5): 

1003 res = api.ScheduleEvent( 

1004 events_pb2.ScheduleEventReq( 

1005 event_id=event_ids[-1], 

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

1007 online_information=events_pb2.OnlineEventInformation( 

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

1009 ), 

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

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

1012 timezone="UTC", 

1013 ) 

1014 ) 

1015 

1016 event_ids.append(res.event_id) 

1017 

1018 updated_event_id = event_ids[3] 

1019 

1020 time_before_update = now() 

1021 

1022 with events_session(token1) as api: 

1023 res = api.UpdateEvent( 

1024 events_pb2.UpdateEventReq( 

1025 event_id=updated_event_id, 

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

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

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

1029 update_all_future=True, 

1030 ) 

1031 ) 

1032 

1033 time_after_update = now() 

1034 

1035 with events_session(token2) as api: 

1036 for i in range(3): 

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

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

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

1040 

1041 for i in range(3, 6): 

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

1043 assert res.content == "New content." 

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

1045 

1046 

1047def test_GetEvent(db): 

1048 # event creator 

1049 user1, token1 = generate_user() 

1050 # community moderator 

1051 user2, token2 = generate_user() 

1052 # third parties 

1053 user3, token3 = generate_user() 

1054 user4, token4 = generate_user() 

1055 user5, token5 = generate_user() 

1056 user6, token6 = generate_user() 

1057 

1058 with session_scope() as session: 

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

1060 

1061 time_before = now() 

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

1063 end_time = start_time + timedelta(hours=3) 

1064 

1065 with events_session(token1) as api: 

1066 # in person event 

1067 res = api.CreateEvent( 

1068 events_pb2.CreateEventReq( 

1069 title="Dummy Title", 

1070 content="Dummy content.", 

1071 offline_information=events_pb2.OfflineEventInformation( 

1072 address="Near Null Island", 

1073 lat=0.1, 

1074 lng=0.2, 

1075 ), 

1076 start_time=Timestamp_from_datetime(start_time), 

1077 end_time=Timestamp_from_datetime(end_time), 

1078 timezone="UTC", 

1079 ) 

1080 ) 

1081 

1082 event_id = res.event_id 

1083 

1084 with events_session(token4) as api: 

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

1086 

1087 with events_session(token5) as api: 

1088 api.SetEventAttendance( 

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

1090 ) 

1091 

1092 with events_session(token6) as api: 

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

1094 api.SetEventAttendance( 

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

1096 ) 

1097 

1098 with events_session(token1) as api: 

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

1100 

1101 assert res.is_next 

1102 assert res.title == "Dummy Title" 

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

1104 assert res.content == "Dummy content." 

1105 assert not res.photo_url 

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

1107 assert res.offline_information.lat == 0.1 

1108 assert res.offline_information.lng == 0.2 

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

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

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

1112 assert res.creator_user_id == user1.id 

1113 assert to_aware_datetime(res.start_time) == start_time 

1114 assert to_aware_datetime(res.end_time) == end_time 

1115 # assert res.timezone == "UTC" 

1116 assert res.start_time_display 

1117 assert res.end_time_display 

1118 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_GOING 

1119 assert res.organizer 

1120 assert res.subscriber 

1121 assert res.going_count == 2 

1122 assert res.maybe_count == 1 

1123 assert res.organizer_count == 1 

1124 assert res.subscriber_count == 3 

1125 assert res.owner_user_id == user1.id 

1126 assert not res.owner_community_id 

1127 assert not res.owner_group_id 

1128 assert res.thread.thread_id 

1129 assert res.can_edit 

1130 assert not res.can_moderate 

1131 

1132 with events_session(token2) as api: 

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

1134 

1135 assert res.is_next 

1136 assert res.title == "Dummy Title" 

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

1138 assert res.content == "Dummy content." 

1139 assert not res.photo_url 

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

1141 assert res.offline_information.lat == 0.1 

1142 assert res.offline_information.lng == 0.2 

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

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

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

1146 assert res.creator_user_id == user1.id 

1147 assert to_aware_datetime(res.start_time) == start_time 

1148 assert to_aware_datetime(res.end_time) == end_time 

1149 # assert res.timezone == "UTC" 

1150 assert res.start_time_display 

1151 assert res.end_time_display 

1152 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

1153 assert not res.organizer 

1154 assert not res.subscriber 

1155 assert res.going_count == 2 

1156 assert res.maybe_count == 1 

1157 assert res.organizer_count == 1 

1158 assert res.subscriber_count == 3 

1159 assert res.owner_user_id == user1.id 

1160 assert not res.owner_community_id 

1161 assert not res.owner_group_id 

1162 assert res.thread.thread_id 

1163 assert not res.can_edit 

1164 assert res.can_moderate 

1165 

1166 with events_session(token3) as api: 

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

1168 

1169 assert res.is_next 

1170 assert res.title == "Dummy Title" 

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

1172 assert res.content == "Dummy content." 

1173 assert not res.photo_url 

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

1175 assert res.offline_information.lat == 0.1 

1176 assert res.offline_information.lng == 0.2 

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

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

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

1180 assert res.creator_user_id == user1.id 

1181 assert to_aware_datetime(res.start_time) == start_time 

1182 assert to_aware_datetime(res.end_time) == end_time 

1183 # assert res.timezone == "UTC" 

1184 assert res.start_time_display 

1185 assert res.end_time_display 

1186 assert res.attendance_state == events_pb2.ATTENDANCE_STATE_NOT_GOING 

1187 assert not res.organizer 

1188 assert not res.subscriber 

1189 assert res.going_count == 2 

1190 assert res.maybe_count == 1 

1191 assert res.organizer_count == 1 

1192 assert res.subscriber_count == 3 

1193 assert res.owner_user_id == user1.id 

1194 assert not res.owner_community_id 

1195 assert not res.owner_group_id 

1196 assert res.thread.thread_id 

1197 assert not res.can_edit 

1198 assert not res.can_moderate 

1199 

1200 

1201def test_ListEventAttendees(db): 

1202 # event creator 

1203 user1, token1 = generate_user() 

1204 # others 

1205 user2, token2 = generate_user() 

1206 user3, token3 = generate_user() 

1207 user4, token4 = generate_user() 

1208 user5, token5 = generate_user() 

1209 user6, token6 = generate_user() 

1210 

1211 with session_scope() as session: 

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

1213 

1214 with events_session(token1) as api: 

1215 event_id = api.CreateEvent( 

1216 events_pb2.CreateEventReq( 

1217 title="Dummy Title", 

1218 content="Dummy content.", 

1219 offline_information=events_pb2.OfflineEventInformation( 

1220 address="Near Null Island", 

1221 lat=0.1, 

1222 lng=0.2, 

1223 ), 

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

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

1226 timezone="UTC", 

1227 ) 

1228 ).event_id 

1229 

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

1231 with events_session(token) as api: 

1232 api.SetEventAttendance( 

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

1234 ) 

1235 

1236 with events_session(token6) as api: 

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

1238 

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

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

1241 

1242 res = api.ListEventAttendees( 

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

1244 ) 

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

1246 

1247 res = api.ListEventAttendees( 

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

1249 ) 

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

1251 assert not res.next_page_token 

1252 

1253 

1254def test_ListEventSubscribers(db): 

1255 # event creator 

1256 user1, token1 = generate_user() 

1257 # others 

1258 user2, token2 = generate_user() 

1259 user3, token3 = generate_user() 

1260 user4, token4 = generate_user() 

1261 user5, token5 = generate_user() 

1262 user6, token6 = generate_user() 

1263 

1264 with session_scope() as session: 

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

1266 

1267 with events_session(token1) as api: 

1268 event_id = api.CreateEvent( 

1269 events_pb2.CreateEventReq( 

1270 title="Dummy Title", 

1271 content="Dummy content.", 

1272 offline_information=events_pb2.OfflineEventInformation( 

1273 address="Near Null Island", 

1274 lat=0.1, 

1275 lng=0.2, 

1276 ), 

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

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

1279 timezone="UTC", 

1280 ) 

1281 ).event_id 

1282 

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

1284 with events_session(token) as api: 

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

1286 

1287 with events_session(token6) as api: 

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

1289 

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

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

1292 

1293 res = api.ListEventSubscribers( 

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

1295 ) 

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

1297 

1298 res = api.ListEventSubscribers( 

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

1300 ) 

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

1302 assert not res.next_page_token 

1303 

1304 

1305def test_ListEventOrganizers(db): 

1306 # event creator 

1307 user1, token1 = generate_user() 

1308 # others 

1309 user2, token2 = generate_user() 

1310 user3, token3 = generate_user() 

1311 user4, token4 = generate_user() 

1312 user5, token5 = generate_user() 

1313 user6, token6 = generate_user() 

1314 

1315 with session_scope() as session: 

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

1317 

1318 with events_session(token1) as api: 

1319 event_id = api.CreateEvent( 

1320 events_pb2.CreateEventReq( 

1321 title="Dummy Title", 

1322 content="Dummy content.", 

1323 offline_information=events_pb2.OfflineEventInformation( 

1324 address="Near Null Island", 

1325 lat=0.1, 

1326 lng=0.2, 

1327 ), 

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

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

1330 timezone="UTC", 

1331 ) 

1332 ).event_id 

1333 

1334 with events_session(token1) as api: 

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

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

1337 

1338 with events_session(token6) as api: 

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

1340 

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

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

1343 

1344 res = api.ListEventOrganizers( 

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

1346 ) 

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

1348 

1349 res = api.ListEventOrganizers( 

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

1351 ) 

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

1353 assert not res.next_page_token 

1354 

1355 

1356def test_TransferEvent(db): 

1357 user1, token1 = generate_user() 

1358 user2, token2 = generate_user() 

1359 user3, token3 = generate_user() 

1360 user4, token4 = generate_user() 

1361 

1362 with session_scope() as session: 

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

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

1365 c_id = c.id 

1366 h_id = h.id 

1367 

1368 with events_session(token1) as api: 

1369 event_id = api.CreateEvent( 

1370 events_pb2.CreateEventReq( 

1371 title="Dummy Title", 

1372 content="Dummy content.", 

1373 offline_information=events_pb2.OfflineEventInformation( 

1374 address="Near Null Island", 

1375 lat=0.1, 

1376 lng=0.2, 

1377 ), 

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

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

1380 timezone="UTC", 

1381 ) 

1382 ).event_id 

1383 

1384 api.TransferEvent( 

1385 events_pb2.TransferEventReq( 

1386 event_id=event_id, 

1387 new_owner_community_id=c_id, 

1388 ) 

1389 ) 

1390 

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

1392 api.TransferEvent( 

1393 events_pb2.TransferEventReq( 

1394 event_id=event_id, 

1395 new_owner_group_id=h_id, 

1396 ) 

1397 ) 

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

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

1400 

1401 event_id = api.CreateEvent( 

1402 events_pb2.CreateEventReq( 

1403 title="Dummy Title", 

1404 content="Dummy content.", 

1405 offline_information=events_pb2.OfflineEventInformation( 

1406 address="Near Null Island", 

1407 lat=0.1, 

1408 lng=0.2, 

1409 ), 

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

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

1412 timezone="UTC", 

1413 ) 

1414 ).event_id 

1415 

1416 api.TransferEvent( 

1417 events_pb2.TransferEventReq( 

1418 event_id=event_id, 

1419 new_owner_group_id=h_id, 

1420 ) 

1421 ) 

1422 

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

1424 api.TransferEvent( 

1425 events_pb2.TransferEventReq( 

1426 event_id=event_id, 

1427 new_owner_community_id=c_id, 

1428 ) 

1429 ) 

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

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

1432 

1433 

1434def test_SetEventSubscription(db): 

1435 user1, token1 = generate_user() 

1436 user2, token2 = generate_user() 

1437 

1438 with session_scope() as session: 

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

1440 

1441 with events_session(token1) as api: 

1442 event_id = api.CreateEvent( 

1443 events_pb2.CreateEventReq( 

1444 title="Dummy Title", 

1445 content="Dummy content.", 

1446 offline_information=events_pb2.OfflineEventInformation( 

1447 address="Near Null Island", 

1448 lat=0.1, 

1449 lng=0.2, 

1450 ), 

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

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

1453 timezone="UTC", 

1454 ) 

1455 ).event_id 

1456 

1457 with events_session(token2) as api: 

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

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

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

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

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

1463 

1464 

1465def test_SetEventAttendance(db): 

1466 user1, token1 = generate_user() 

1467 user2, token2 = generate_user() 

1468 

1469 with session_scope() as session: 

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

1471 

1472 with events_session(token1) as api: 

1473 event_id = api.CreateEvent( 

1474 events_pb2.CreateEventReq( 

1475 title="Dummy Title", 

1476 content="Dummy content.", 

1477 offline_information=events_pb2.OfflineEventInformation( 

1478 address="Near Null Island", 

1479 lat=0.1, 

1480 lng=0.2, 

1481 ), 

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

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

1484 timezone="UTC", 

1485 ) 

1486 ).event_id 

1487 

1488 with events_session(token2) as api: 

1489 assert ( 

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

1491 == events_pb2.ATTENDANCE_STATE_NOT_GOING 

1492 ) 

1493 api.SetEventAttendance( 

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

1495 ) 

1496 assert ( 

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

1498 == events_pb2.ATTENDANCE_STATE_GOING 

1499 ) 

1500 api.SetEventAttendance( 

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

1502 ) 

1503 assert ( 

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

1505 == events_pb2.ATTENDANCE_STATE_MAYBE 

1506 ) 

1507 api.SetEventAttendance( 

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

1509 ) 

1510 assert ( 

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

1512 == events_pb2.ATTENDANCE_STATE_NOT_GOING 

1513 ) 

1514 

1515 

1516def test_InviteEventOrganizer(db): 

1517 user1, token1 = generate_user() 

1518 user2, token2 = generate_user() 

1519 

1520 with session_scope() as session: 

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

1522 

1523 with events_session(token1) as api: 

1524 event_id = api.CreateEvent( 

1525 events_pb2.CreateEventReq( 

1526 title="Dummy Title", 

1527 content="Dummy content.", 

1528 offline_information=events_pb2.OfflineEventInformation( 

1529 address="Near Null Island", 

1530 lat=0.1, 

1531 lng=0.2, 

1532 ), 

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

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

1535 timezone="UTC", 

1536 ) 

1537 ).event_id 

1538 

1539 with events_session(token2) as api: 

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

1541 

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

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

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

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

1546 

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

1548 

1549 with events_session(token1) as api: 

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

1551 

1552 with events_session(token2) as api: 

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

1554 

1555 

1556def test_ListEventOccurrences(db): 

1557 user1, token1 = generate_user() 

1558 user2, token2 = generate_user() 

1559 user3, token3 = generate_user() 

1560 

1561 with session_scope() as session: 

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

1563 

1564 time_before = now() 

1565 start = now() 

1566 

1567 event_ids = [] 

1568 

1569 with events_session(token1) as api: 

1570 res = api.CreateEvent( 

1571 events_pb2.CreateEventReq( 

1572 title="First occurrence", 

1573 content="Dummy content.", 

1574 parent_community_id=c_id, 

1575 online_information=events_pb2.OnlineEventInformation( 

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

1577 ), 

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

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

1580 timezone="UTC", 

1581 ) 

1582 ) 

1583 

1584 event_ids.append(res.event_id) 

1585 

1586 for i in range(5): 

1587 res = api.ScheduleEvent( 

1588 events_pb2.ScheduleEventReq( 

1589 event_id=event_ids[-1], 

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

1591 online_information=events_pb2.OnlineEventInformation( 

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

1593 ), 

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

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

1596 timezone="UTC", 

1597 ) 

1598 ) 

1599 

1600 event_ids.append(res.event_id) 

1601 

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

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

1604 

1605 res = api.ListEventOccurrences( 

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

1607 ) 

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

1609 

1610 res = api.ListEventOccurrences( 

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

1612 ) 

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

1614 assert not res.next_page_token 

1615 

1616 

1617def test_ListMyEvents(db): 

1618 user1, token1 = generate_user() 

1619 user2, token2 = generate_user() 

1620 user3, token3 = generate_user() 

1621 user4, token4 = generate_user() 

1622 user5, token5 = generate_user() 

1623 

1624 with session_scope() as session: 

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

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

1627 

1628 start = now() 

1629 

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

1631 if online: 

1632 return events_pb2.CreateEventReq( 

1633 title="Dummy Online Title", 

1634 content="Dummy content.", 

1635 online_information=events_pb2.OnlineEventInformation( 

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

1637 ), 

1638 parent_community_id=community_id, 

1639 timezone="UTC", 

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

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

1642 ) 

1643 else: 

1644 return events_pb2.CreateEventReq( 

1645 title="Dummy Offline Title", 

1646 content="Dummy content.", 

1647 offline_information=events_pb2.OfflineEventInformation( 

1648 address="Near Null Island", 

1649 lat=0.1, 

1650 lng=0.2, 

1651 ), 

1652 timezone="UTC", 

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

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

1655 ) 

1656 

1657 with events_session(token1) as api: 

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

1659 

1660 with events_session(token2) as api: 

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

1662 

1663 with events_session(token1) as api: 

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

1665 

1666 with events_session(token2) as api: 

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

1668 

1669 with events_session(token3) as api: 

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

1671 

1672 with events_session(token4) as api: 

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

1674 

1675 with events_session(token1) as api: 

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

1677 

1678 with events_session(token1) as api: 

1679 api.SetEventAttendance( 

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

1681 ) 

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

1683 

1684 with events_session(token2) as api: 

1685 api.SetEventAttendance( 

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

1687 ) 

1688 

1689 with events_session(token3) as api: 

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

1691 

1692 with events_session(token1) as api: 

1693 # test pagination first 

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

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

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

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

1698 assert not res.next_page_token 

1699 

1700 res = api.ListMyEvents( 

1701 events_pb2.ListMyEventsReq( 

1702 subscribed=True, 

1703 attending=True, 

1704 organizing=True, 

1705 ) 

1706 ) 

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

1708 

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

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

1711 

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

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

1714 

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

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

1717 

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

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

1720 

1721 with events_session(token2) as api: 

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

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

1724 

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

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

1727 

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

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

1730 

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

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

1733 

1734 with events_session(token3) as api: 

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

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

1737 

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

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

1740 

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

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

1743 

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

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

1746 

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

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

1749 

1750 with events_session(token5) as api: 

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

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

1753 

1754 

1755def test_RemoveEventOrganizer(db): 

1756 user1, token1 = generate_user() 

1757 user2, token2 = generate_user() 

1758 

1759 with session_scope() as session: 

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

1761 

1762 with events_session(token1) as api: 

1763 event_id = api.CreateEvent( 

1764 events_pb2.CreateEventReq( 

1765 title="Dummy Title", 

1766 content="Dummy content.", 

1767 offline_information=events_pb2.OfflineEventInformation( 

1768 address="Near Null Island", 

1769 lat=0.1, 

1770 lng=0.2, 

1771 ), 

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

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

1774 timezone="UTC", 

1775 ) 

1776 ).event_id 

1777 

1778 with events_session(token2) as api: 

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

1780 

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

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

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

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

1785 

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

1787 

1788 with events_session(token1) as api: 

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

1790 

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

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

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

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

1795 

1796 with events_session(token2) as api: 

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

1798 assert res.organizer 

1799 assert res.organizer_count == 2 

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

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

1802 

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

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

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

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

1807 

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

1809 assert not res.organizer 

1810 assert res.organizer_count == 1 

1811 

1812 

1813def test_ListEventAttendees_regression(db): 

1814 # see issue #1617: 

1815 # 

1816 # 1. Create an event 

1817 # 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` 

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

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

1820 # 

1821 # **Expected behaviour** 

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

1823 # 

1824 # **Actual/current behaviour** 

1825 # `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 

1826 

1827 user1, token1 = generate_user() 

1828 user2, token2 = generate_user() 

1829 user3, token3 = generate_user() 

1830 user4, token4 = generate_user() 

1831 user5, token5 = generate_user() 

1832 

1833 with session_scope() as session: 

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

1835 

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

1837 end_time = start_time + timedelta(hours=3) 

1838 

1839 with events_session(token1) as api: 

1840 res = api.CreateEvent( 

1841 events_pb2.CreateEventReq( 

1842 title="Dummy Title", 

1843 content="Dummy content.", 

1844 online_information=events_pb2.OnlineEventInformation( 

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

1846 ), 

1847 parent_community_id=c_id, 

1848 start_time=Timestamp_from_datetime(start_time), 

1849 end_time=Timestamp_from_datetime(end_time), 

1850 timezone="UTC", 

1851 ) 

1852 ) 

1853 

1854 res = api.TransferEvent( 

1855 events_pb2.TransferEventReq( 

1856 event_id=res.event_id, 

1857 new_owner_community_id=c_id, 

1858 ) 

1859 ) 

1860 

1861 event_id = res.event_id 

1862 

1863 api.SetEventAttendance( 

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

1865 ) 

1866 api.SetEventAttendance( 

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

1868 ) 

1869 

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

1871 assert len(res.attendee_user_ids) == 1 

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

1873 

1874 

1875def test_event_threads(db): 

1876 user1, token1 = generate_user() 

1877 user2, token2 = generate_user() 

1878 user3, token3 = generate_user() 

1879 user4, token4 = generate_user() 

1880 

1881 with session_scope() as session: 

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

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

1884 c_id = c.id 

1885 h_id = h.id 

1886 

1887 with events_session(token1) as api: 

1888 event = api.CreateEvent( 

1889 events_pb2.CreateEventReq( 

1890 title="Dummy Title", 

1891 content="Dummy content.", 

1892 offline_information=events_pb2.OfflineEventInformation( 

1893 address="Near Null Island", 

1894 lat=0.1, 

1895 lng=0.2, 

1896 ), 

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

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

1899 timezone="UTC", 

1900 ) 

1901 ) 

1902 

1903 with threads_session(token2) as api: 

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

1905 

1906 with events_session(token3) as api: 

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

1908 assert res.thread.num_responses == 1 

1909 

1910 with threads_session(token3) as api: 

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

1912 assert len(ret.replies) == 1 

1913 assert not ret.next_page_token 

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

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

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

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

1918 

1919 

1920def test_can_overlap_other_events_schedule_regression(db): 

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

1922 user, token = generate_user() 

1923 

1924 with session_scope() as session: 

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

1926 

1927 start = now() 

1928 

1929 with events_session(token) as api: 

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

1931 api.CreateEvent( 

1932 events_pb2.CreateEventReq( 

1933 title="Dummy Title", 

1934 content="Dummy content.", 

1935 parent_community_id=c_id, 

1936 online_information=events_pb2.OnlineEventInformation( 

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

1938 ), 

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

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

1941 timezone="UTC", 

1942 ) 

1943 ) 

1944 

1945 # this event 

1946 res = api.CreateEvent( 

1947 events_pb2.CreateEventReq( 

1948 title="Dummy Title", 

1949 content="Dummy content.", 

1950 parent_community_id=c_id, 

1951 online_information=events_pb2.OnlineEventInformation( 

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

1953 ), 

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

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

1956 timezone="UTC", 

1957 ) 

1958 ) 

1959 

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

1961 api.ScheduleEvent( 

1962 events_pb2.ScheduleEventReq( 

1963 event_id=res.event_id, 

1964 content="New event occurrence", 

1965 offline_information=events_pb2.OfflineEventInformation( 

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

1967 lat=0.3, 

1968 lng=0.2, 

1969 ), 

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

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

1972 timezone="UTC", 

1973 ) 

1974 ) 

1975 

1976 

1977def test_can_overlap_other_events_update_regression(db): 

1978 user, token = generate_user() 

1979 

1980 with session_scope() as session: 

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

1982 

1983 start = now() 

1984 

1985 with events_session(token) as api: 

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

1987 api.CreateEvent( 

1988 events_pb2.CreateEventReq( 

1989 title="Dummy Title", 

1990 content="Dummy content.", 

1991 parent_community_id=c_id, 

1992 online_information=events_pb2.OnlineEventInformation( 

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

1994 ), 

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

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

1997 timezone="UTC", 

1998 ) 

1999 ) 

2000 

2001 res = api.CreateEvent( 

2002 events_pb2.CreateEventReq( 

2003 title="Dummy Title", 

2004 content="Dummy content.", 

2005 parent_community_id=c_id, 

2006 online_information=events_pb2.OnlineEventInformation( 

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

2008 ), 

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

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

2011 timezone="UTC", 

2012 ) 

2013 ) 

2014 

2015 event_id = api.ScheduleEvent( 

2016 events_pb2.ScheduleEventReq( 

2017 event_id=res.event_id, 

2018 content="New event occurrence", 

2019 offline_information=events_pb2.OfflineEventInformation( 

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

2021 lat=0.3, 

2022 lng=0.2, 

2023 ), 

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

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

2026 timezone="UTC", 

2027 ) 

2028 ).event_id 

2029 

2030 # can overlap with this current existing occurrence 

2031 api.UpdateEvent( 

2032 events_pb2.UpdateEventReq( 

2033 event_id=event_id, 

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

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

2036 ) 

2037 ) 

2038 

2039 api.UpdateEvent( 

2040 events_pb2.UpdateEventReq( 

2041 event_id=event_id, 

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

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

2044 ) 

2045 ) 

2046 

2047 

2048def test_list_past_events_regression(db): 

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

2050 user, token = generate_user() 

2051 

2052 with session_scope() as session: 

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

2054 

2055 start = now() 

2056 

2057 with events_session(token) as api: 

2058 api.CreateEvent( 

2059 events_pb2.CreateEventReq( 

2060 title="Dummy Title", 

2061 content="Dummy content.", 

2062 parent_community_id=c_id, 

2063 online_information=events_pb2.OnlineEventInformation( 

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

2065 ), 

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

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

2068 timezone="UTC", 

2069 ) 

2070 ) 

2071 

2072 with session_scope() as session: 

2073 session.execute( 

2074 update(EventOccurrence).values( 

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

2076 ) 

2077 ) 

2078 

2079 with events_session(token) as api: 

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

2081 assert len(res.events) == 1