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
« prev ^ index » next coverage.py v7.6.10, created at 2025-03-11 15:27 +0000
1from datetime import timedelta
3import grpc
4import pytest
5from google.protobuf import wrappers_pb2
6from psycopg2.extras import DateTimeTZRange
7from sqlalchemy.sql.expression import update
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)
30@pytest.fixture(autouse=True)
31def _(testconfig):
32 pass
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
44 # event creator
45 user1, token1 = generate_user()
46 # community moderator
47 user2, token2 = generate_user()
48 # third party
49 user3, token3 = generate_user()
51 with session_scope() as session:
52 c_id = create_community(session, 0, 2, "Community", [user2], [], None).id
54 time_before = now()
55 start_time = now() + timedelta(hours=2)
56 end_time = start_time + timedelta(hours=3)
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 )
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
107 event_id = res.event_id
109 with events_session(token2) as api:
110 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
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
143 with events_session(token3) as api:
144 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
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
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 )
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
223 event_id = res.event_id
225 with events_session(token2) as api:
226 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
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
257 with events_session(token3) as api:
258 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
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
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
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
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
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
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
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
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
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
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
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
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
483def test_CreateEvent_incomplete_profile(db):
484 user1, token1 = generate_user(complete_profile=False)
485 user2, token2 = generate_user()
487 with session_scope() as session:
488 c_id = create_community(session, 0, 2, "Community", [user2], [], None).id
490 start_time = now() + timedelta(hours=2)
491 end_time = start_time + timedelta(hours=3)
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
514def test_ScheduleEvent(db):
515 # test cases:
516 # can schedule a new event occurrence
518 user, token = generate_user()
520 with session_scope() as session:
521 c_id = create_community(session, 0, 2, "Community", [user], [], None).id
523 time_before = now()
524 start_time = now() + timedelta(hours=2)
525 end_time = start_time + timedelta(hours=3)
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 )
542 new_start_time = now() + timedelta(hours=6)
543 new_end_time = new_start_time + timedelta(hours=2)
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 )
560 res = api.GetEvent(events_pb2.GetEventReq(event_id=res.event_id))
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
594def test_cannot_overlap_occurrences_schedule(db):
595 user, token = generate_user()
597 with session_scope() as session:
598 c_id = create_community(session, 0, 2, "Community", [user], [], None).id
600 start = now()
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 )
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
636def test_cannot_overlap_occurrences_update(db):
637 user, token = generate_user()
639 with session_scope() as session:
640 c_id = create_community(session, 0, 2, "Community", [user], [], None).id
642 start = now()
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 )
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
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 )
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
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
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()
712 with session_scope() as session:
713 c_id = create_community(session, 0, 2, "Community", [user2], [], None).id
715 time_before = now()
716 start_time = now() + timedelta(hours=2)
717 end_time = start_time + timedelta(hours=3)
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 )
735 event_id = res.event_id
737 with events_session(token4) as api:
738 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True))
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 )
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 )
751 time_before_update = now()
753 with events_session(token1) as api:
754 res = api.UpdateEvent(
755 events_pb2.UpdateEventReq(
756 event_id=event_id,
757 )
758 )
760 with events_session(token1) as api:
761 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
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
794 with events_session(token2) as api:
795 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
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
828 with events_session(token3) as api:
829 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
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
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 )
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
904 event_id = res.event_id
906 with events_session(token2) as api:
907 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
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
938 with events_session(token3) as api:
939 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
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
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 )
982 with events_session(token3) as api:
983 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
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
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()
1002 with session_scope() as session:
1003 c_id = create_community(session, 0, 2, "Community", [user2], [], None).id
1005 time_before = now()
1006 start_time = now() + timedelta(hours=1)
1007 end_time = start_time + timedelta(hours=1.5)
1009 event_ids = []
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 )
1027 event_id = res.event_id
1028 event_ids.append(event_id)
1030 with events_session(token4) as api:
1031 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True))
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 )
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 )
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 )
1059 event_ids.append(res.event_id)
1061 updated_event_id = event_ids[3]
1063 time_before_update = now()
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 )
1076 time_after_update = now()
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
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
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()
1101 with session_scope() as session:
1102 c_id = create_community(session, 0, 2, "Community", [user2], [], None).id
1104 time_before = now()
1105 start_time = now() + timedelta(hours=2)
1106 end_time = start_time + timedelta(hours=3)
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 )
1125 event_id = res.event_id
1127 with events_session(token4) as api:
1128 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True))
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 )
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 )
1141 with events_session(token1) as api:
1142 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
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
1175 with events_session(token2) as api:
1176 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
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
1209 with events_session(token3) as api:
1210 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
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
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()
1255 with session_scope() as session:
1256 c_id = create_community(session, 0, 2, "Community", [user2], [], None).id
1258 start_time = now() + timedelta(hours=2)
1259 end_time = start_time + timedelta(hours=3)
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 )
1277 event_id = res.event_id
1279 with events_session(token4) as api:
1280 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=event_id, subscribe=True))
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 )
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 )
1293 with events_session(token1) as api:
1294 res = api.CancelEvent(
1295 events_pb2.CancelEventReq(
1296 event_id=event_id,
1297 )
1298 )
1300 with events_session(token1) as api:
1301 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
1302 assert res.is_cancelled
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
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
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
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
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
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
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
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()
1377 with session_scope() as session:
1378 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id
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
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 )
1402 with events_session(token6) as api:
1403 assert api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).going_count == 5
1405 res = api.ListEventAttendees(events_pb2.ListEventAttendeesReq(event_id=event_id, page_size=2))
1406 assert res.attendee_user_ids == [user1.id, user2.id]
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]
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
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()
1430 with session_scope() as session:
1431 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id
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
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))
1453 with events_session(token6) as api:
1454 assert api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).subscriber_count == 5
1456 res = api.ListEventSubscribers(events_pb2.ListEventSubscribersReq(event_id=event_id, page_size=2))
1457 assert res.subscriber_user_ids == [user1.id, user2.id]
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]
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
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()
1481 with session_scope() as session:
1482 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id
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
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))
1504 with events_session(token6) as api:
1505 assert api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).organizer_count == 5
1507 res = api.ListEventOrganizers(events_pb2.ListEventOrganizersReq(event_id=event_id, page_size=2))
1508 assert res.organizer_user_ids == [user1.id, user2.id]
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]
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
1522def test_TransferEvent(db):
1523 user1, token1 = generate_user()
1524 user2, token2 = generate_user()
1525 user3, token3 = generate_user()
1526 user4, token4 = generate_user()
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
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
1550 api.TransferEvent(
1551 events_pb2.TransferEventReq(
1552 event_id=event_id,
1553 new_owner_community_id=c_id,
1554 )
1555 )
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
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
1582 api.TransferEvent(
1583 events_pb2.TransferEventReq(
1584 event_id=event_id,
1585 new_owner_group_id=h_id,
1586 )
1587 )
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
1600def test_SetEventSubscription(db):
1601 user1, token1 = generate_user()
1602 user2, token2 = generate_user()
1604 with session_scope() as session:
1605 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id
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
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
1631def test_SetEventAttendance(db):
1632 user1, token1 = generate_user()
1633 user2, token2 = generate_user()
1635 with session_scope() as session:
1636 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id
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
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 )
1682def test_InviteEventOrganizer(db):
1683 user1, token1 = generate_user()
1684 user2, token2 = generate_user()
1686 with session_scope() as session:
1687 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id
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
1705 with events_session(token2) as api:
1706 assert not api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).organizer
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
1713 assert not api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).organizer
1715 with events_session(token1) as api:
1716 api.InviteEventOrganizer(events_pb2.InviteEventOrganizerReq(event_id=event_id, user_id=user2.id))
1718 with events_session(token2) as api:
1719 assert api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).organizer
1722def test_ListEventOccurrences(db):
1723 user1, token1 = generate_user()
1724 user2, token2 = generate_user()
1725 user3, token3 = generate_user()
1727 with session_scope() as session:
1728 c_id = create_community(session, 0, 2, "Community", [user2], [], None).id
1730 start = now()
1732 event_ids = []
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 )
1749 event_ids.append(res.event_id)
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 )
1765 event_ids.append(res.event_id)
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]
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]
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
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()
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
1793 start = now()
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 )
1822 with events_session(token1) as api:
1823 e2 = api.CreateEvent(new_event(2, c_id, True)).event_id
1825 with events_session(token2) as api:
1826 e1 = api.CreateEvent(new_event(1, c_id, False)).event_id
1828 with events_session(token1) as api:
1829 e3 = api.CreateEvent(new_event(3, c_id, False)).event_id
1831 with events_session(token2) as api:
1832 e5 = api.CreateEvent(new_event(5, c_id, True)).event_id
1834 with events_session(token3) as api:
1835 e4 = api.CreateEvent(new_event(4, c_id, True)).event_id
1837 with events_session(token4) as api:
1838 e6 = api.CreateEvent(new_event(6, c2_id, True)).event_id
1840 with events_session(token1) as api:
1841 api.InviteEventOrganizer(events_pb2.InviteEventOrganizerReq(event_id=e3, user_id=user3.id))
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))
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 )
1854 with events_session(token3) as api:
1855 api.SetEventSubscription(events_pb2.SetEventSubscriptionReq(event_id=e2, subscribe=True))
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
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]
1874 res = api.ListMyEvents(events_pb2.ListMyEventsReq())
1875 assert [event.event_id for event in res.events] == [e1, e2, e3, e4]
1877 res = api.ListMyEvents(events_pb2.ListMyEventsReq(subscribed=True))
1878 assert [event.event_id for event in res.events] == [e2, e3, e4]
1880 res = api.ListMyEvents(events_pb2.ListMyEventsReq(attending=True))
1881 assert [event.event_id for event in res.events] == [e1, e2, e3]
1883 res = api.ListMyEvents(events_pb2.ListMyEventsReq(organizing=True))
1884 assert [event.event_id for event in res.events] == [e2, e3]
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
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
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
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]
1911 res = api.ListMyEvents(events_pb2.ListMyEventsReq(subscribed=True))
1912 assert [event.event_id for event in res.events] == [e1, e5]
1914 res = api.ListMyEvents(events_pb2.ListMyEventsReq(attending=True))
1915 assert [event.event_id for event in res.events] == [e1, e3, e5]
1917 res = api.ListMyEvents(events_pb2.ListMyEventsReq(organizing=True))
1918 assert [event.event_id for event in res.events] == [e1, e5]
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]
1924 res = api.ListMyEvents(events_pb2.ListMyEventsReq(subscribed=True))
1925 assert [event.event_id for event in res.events] == [e2, e4]
1927 res = api.ListMyEvents(events_pb2.ListMyEventsReq(attending=True))
1928 assert [event.event_id for event in res.events] == [e4]
1930 res = api.ListMyEvents(events_pb2.ListMyEventsReq(organizing=True))
1931 assert [event.event_id for event in res.events] == [e3, e4]
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]
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]
1941def test_RemoveEventOrganizer(db):
1942 user1, token1 = generate_user()
1943 user2, token2 = generate_user()
1945 with session_scope() as session:
1946 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id
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
1964 with events_session(token2) as api:
1965 assert not api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).organizer
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
1972 assert not api.GetEvent(events_pb2.GetEventReq(event_id=event_id)).organizer
1974 with events_session(token1) as api:
1975 api.InviteEventOrganizer(events_pb2.InviteEventOrganizerReq(event_id=event_id, user_id=user2.id))
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
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
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
1994 res = api.GetEvent(events_pb2.GetEventReq(event_id=event_id))
1995 assert not res.organizer
1996 assert res.organizer_count == 1
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
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()
2019 with session_scope() as session:
2020 c_id = create_community(session, 0, 2, "Community", [user1], [], None).id
2022 start_time = now() + timedelta(hours=2)
2023 end_time = start_time + timedelta(hours=3)
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 )
2040 res = api.TransferEvent(
2041 events_pb2.TransferEventReq(
2042 event_id=res.event_id,
2043 new_owner_community_id=c_id,
2044 )
2045 )
2047 event_id = res.event_id
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 )
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
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()
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
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 )
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
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
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
2106 api.PostReply(threads_pb2.PostReplyReq(thread_id=reply_id, content="what a silly comment"))
2108 process_jobs()
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)
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()
2119 with session_scope() as session:
2120 c_id = create_community(session, 0, 2, "Community", [user], [], None).id
2122 start = now()
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 )
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 )
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 )
2172def test_can_overlap_other_events_update_regression(db):
2173 user, token = generate_user()
2175 with session_scope() as session:
2176 c_id = create_community(session, 0, 2, "Community", [user], [], None).id
2178 start = now()
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 )
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 )
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
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 )
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 )
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()
2247 with session_scope() as session:
2248 c_id = create_community(session, 0, 2, "Community", [user], [], None).id
2250 start = now()
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 )
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 )
2274 with events_session(token) as api:
2275 res = api.ListAllEvents(events_pb2.ListAllEventsReq(past=True))
2276 assert len(res.events) == 1
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)
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
2290 enforce_community_memberships()
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}"
2309 event_id = res.event_id
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"
2317 assert user_url in e.plain
2318 assert event_url in e.plain
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
2326 # another user can send one though
2327 with events_session(token3) as api:
2328 api.RequestCommunityInvite(events_pb2.RequestCommunityInviteReq(event_id=event_id))
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
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
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 )
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 )
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