Coverage for src/tests/test_communities.py: 100%
662 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-12-06 23:17 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-12-06 23:17 +0000
1from datetime import timedelta
3import grpc
4import pytest
5from geoalchemy2 import WKBElement
6from google.protobuf import wrappers_pb2
7from sqlalchemy.orm import Session
9from couchers.db import is_user_in_node_geography, session_scope
10from couchers.materialized_views import refresh_materialized_views
11from couchers.models import (
12 Cluster,
13 ClusterRole,
14 ClusterSubscription,
15 Node,
16 Page,
17 PageType,
18 PageVersion,
19 SignupFlow,
20 Thread,
21)
22from couchers.proto import api_pb2, auth_pb2, communities_pb2, discussions_pb2, events_pb2, pages_pb2
23from couchers.sql import couchers_select as select
24from couchers.tasks import enforce_community_memberships
25from couchers.utils import Timestamp_from_datetime, create_coordinate, create_polygon_lat_lng, now, to_multi
26from tests.test_auth import get_session_cookie_tokens
27from tests.test_fixtures import ( # noqa
28 auth_api_session,
29 communities_session,
30 db,
31 discussions_session,
32 events_session,
33 generate_user,
34 get_user_id_and_token,
35 pages_session,
36 testconfig,
37)
40@pytest.fixture(autouse=True)
41def _(testconfig):
42 pass
45# For testing purposes, restrict ourselves to a 1D-world, consisting of "intervals" that have width 2, and coordinates
46# that are points at (x, 1).
47# we'll stick to EPSG4326, even though it's not ideal, so don't use too large values, but it's around the equator, so
48# mostly fine
51def create_1d_polygon(lb: int, ub: int) -> WKBElement:
52 # given a lower bound and upper bound on x, creates the given interval
53 return create_polygon_lat_lng([[lb, 0], [lb, 2], [ub, 2], [ub, 0], [lb, 0]])
56def create_1d_point(x: int) -> WKBElement:
57 return create_coordinate(x, 1)
60def create_community(session, interval_lb, interval_ub, name, admins, extra_members, parent):
61 node = Node(
62 geom=to_multi(create_1d_polygon(interval_lb, interval_ub)),
63 parent_node=parent,
64 )
65 session.add(node)
66 cluster = Cluster(
67 name=f"{name}",
68 description=f"Description for {name}",
69 parent_node=node,
70 is_official_cluster=True,
71 )
72 session.add(cluster)
73 main_page = Page(
74 parent_node=cluster.parent_node,
75 creator_user_id=admins[0].id,
76 owner_cluster=cluster,
77 type=PageType.main_page,
78 thread=Thread(),
79 )
80 session.add(main_page)
81 page_version = PageVersion(
82 page=main_page,
83 editor_user_id=admins[0].id,
84 title=f"Main page for the {name} community",
85 content="There is nothing here yet...",
86 )
87 session.add(page_version)
88 for admin in admins:
89 cluster.cluster_subscriptions.append(
90 ClusterSubscription(
91 user_id=admin.id,
92 role=ClusterRole.admin,
93 )
94 )
95 for member in extra_members:
96 cluster.cluster_subscriptions.append(
97 ClusterSubscription(
98 user_id=member.id,
99 role=ClusterRole.member,
100 )
101 )
102 session.commit()
103 # other members will be added by enforce_community_memberships()
104 return node
107def create_group(session, name, admins, members, parent_community):
108 cluster = Cluster(
109 name=f"{name}",
110 description=f"Description for {name}",
111 parent_node=parent_community,
112 )
113 session.add(cluster)
114 main_page = Page(
115 parent_node=cluster.parent_node,
116 creator_user=admins[0],
117 owner_cluster=cluster,
118 type=PageType.main_page,
119 thread=Thread(),
120 )
121 session.add(main_page)
122 page_version = PageVersion(
123 page=main_page,
124 editor_user=admins[0],
125 title=f"Main page for the {name} community",
126 content="There is nothing here yet...",
127 )
128 session.add(page_version)
129 for admin in admins:
130 cluster.cluster_subscriptions.append(
131 ClusterSubscription(
132 user=admin,
133 role=ClusterRole.admin,
134 )
135 )
136 for member in members:
137 cluster.cluster_subscriptions.append(
138 ClusterSubscription(
139 user=member,
140 role=ClusterRole.member,
141 )
142 )
143 session.commit()
144 return cluster
147def create_place(token, title, content, address, x):
148 with pages_session(token) as api:
149 res = api.CreatePlace(
150 pages_pb2.CreatePlaceReq(
151 title=title,
152 content=content,
153 address=address,
154 location=pages_pb2.Coordinate(
155 lat=x,
156 lng=1,
157 ),
158 )
159 )
162def create_discussion(token, community_id, group_id, title, content):
163 # set group_id or community_id to None
164 with discussions_session(token) as api:
165 res = api.CreateDiscussion(
166 discussions_pb2.CreateDiscussionReq(
167 title=title,
168 content=content,
169 owner_community_id=community_id,
170 owner_group_id=group_id,
171 )
172 )
175def create_event(token, community_id, group_id, title, content, start_td):
176 with events_session(token) as api:
177 res = api.CreateEvent(
178 events_pb2.CreateEventReq(
179 title=title,
180 content=content,
181 offline_information=events_pb2.OfflineEventInformation(
182 address="Near Null Island",
183 lat=0.1,
184 lng=0.2,
185 ),
186 start_time=Timestamp_from_datetime(now() + start_td),
187 end_time=Timestamp_from_datetime(now() + start_td + timedelta(hours=2)),
188 timezone="UTC",
189 )
190 )
191 api.TransferEvent(
192 events_pb2.TransferEventReq(
193 event_id=res.event_id,
194 new_owner_community_id=community_id,
195 new_owner_group_id=group_id,
196 )
197 )
200def get_community_id(session: Session, community_name: str) -> int:
201 return session.execute(
202 select(Cluster.parent_node_id).where(Cluster.is_official_cluster).where(Cluster.name == community_name)
203 ).scalar_one()
206def get_group_id(session: Session, group_name: str) -> int:
207 return session.execute(
208 select(Cluster.id).where(~Cluster.is_official_cluster).where(Cluster.name == group_name)
209 ).scalar_one()
212@pytest.fixture(scope="class")
213def testing_communities(db_class, testconfig):
214 user1, token1 = generate_user(username="user1", geom=create_1d_point(1), geom_radius=0.1)
215 user2, token2 = generate_user(username="user2", geom=create_1d_point(2), geom_radius=0.1)
216 user3, token3 = generate_user(username="user3", geom=create_1d_point(3), geom_radius=0.1)
217 user4, token4 = generate_user(username="user4", geom=create_1d_point(8), geom_radius=0.1)
218 user5, token5 = generate_user(username="user5", geom=create_1d_point(6), geom_radius=0.1)
219 user6, token6 = generate_user(username="user6", geom=create_1d_point(65), geom_radius=0.1)
220 user7, token7 = generate_user(username="user7", geom=create_1d_point(80), geom_radius=0.1)
221 user8, token8 = generate_user(username="user8", geom=create_1d_point(51), geom_radius=0.1)
223 with session_scope() as session:
224 w = create_community(session, 0, 100, "Global", [user1, user3, user7], [], None)
225 c2 = create_community(session, 52, 100, "Country 2", [user6, user7], [], w)
226 c2r1 = create_community(session, 52, 71, "Country 2, Region 1", [user6], [user8], c2)
227 c2r1c1 = create_community(session, 53, 70, "Country 2, Region 1, City 1", [user8], [], c2r1)
228 c1 = create_community(session, 0, 50, "Country 1", [user1, user2], [], w)
229 c1r1 = create_community(session, 0, 10, "Country 1, Region 1", [user1, user2], [], c1)
230 c1r1c1 = create_community(session, 0, 5, "Country 1, Region 1, City 1", [user2], [], c1r1)
231 c1r1c2 = create_community(session, 7, 10, "Country 1, Region 1, City 2", [user4, user5], [user2], c1r1)
232 c1r2 = create_community(session, 20, 25, "Country 1, Region 2", [user2], [], c1)
233 c1r2c1 = create_community(session, 21, 23, "Country 1, Region 2, City 1", [user2], [], c1r2)
235 h = create_group(session, "Hitchhikers", [user1, user2], [user5, user8], w)
236 create_group(session, "Country 1, Region 1, Foodies", [user1], [user2, user4], c1r1)
237 create_group(session, "Country 1, Region 1, Skaters", [user2], [user1], c1r1)
238 create_group(session, "Country 1, Region 2, Foodies", [user2], [user4, user5], c1r2)
239 create_group(session, "Country 2, Region 1, Foodies", [user6], [user7], c2r1)
241 w_id = w.id
242 c1r1c2_id = c1r1c2.id
243 h_id = h.id
244 c1_id = c1.id
246 create_discussion(token1, w_id, None, "Discussion title 1", "Discussion content 1")
247 create_discussion(token3, w_id, None, "Discussion title 2", "Discussion content 2")
248 create_discussion(token3, w_id, None, "Discussion title 3", "Discussion content 3")
249 create_discussion(token3, w_id, None, "Discussion title 4", "Discussion content 4")
250 create_discussion(token3, w_id, None, "Discussion title 5", "Discussion content 5")
251 create_discussion(token3, w_id, None, "Discussion title 6", "Discussion content 6")
252 create_discussion(token4, c1r1c2_id, None, "Discussion title 7", "Discussion content 7")
253 create_discussion(token5, None, h_id, "Discussion title 8", "Discussion content 8")
254 create_discussion(token1, None, h_id, "Discussion title 9", "Discussion content 9")
255 create_discussion(token2, None, h_id, "Discussion title 10", "Discussion content 10")
256 create_discussion(token3, None, h_id, "Discussion title 11", "Discussion content 11")
257 create_discussion(token4, None, h_id, "Discussion title 12", "Discussion content 12")
258 create_discussion(token5, None, h_id, "Discussion title 13", "Discussion content 13")
259 create_discussion(token8, None, h_id, "Discussion title 14", "Discussion content 14")
261 create_event(token3, c1_id, None, "Event title 1", "Event content 1", timedelta(hours=1))
262 create_event(token1, c1_id, None, "Event title 2", "Event content 2", timedelta(hours=2))
263 create_event(token3, c1_id, None, "Event title 3", "Event content 3", timedelta(hours=3))
264 create_event(token1, c1_id, None, "Event title 4", "Event content 4", timedelta(hours=4))
265 create_event(token3, c1_id, None, "Event title 5", "Event content 5", timedelta(hours=5))
266 create_event(token1, c1_id, None, "Event title 6", "Event content 6", timedelta(hours=6))
267 create_event(token2, None, h_id, "Event title 7", "Event content 7", timedelta(hours=7))
268 create_event(token2, None, h_id, "Event title 8", "Event content 8", timedelta(hours=8))
269 create_event(token2, None, h_id, "Event title 9", "Event content 9", timedelta(hours=9))
270 create_event(token2, None, h_id, "Event title 10", "Event content 10", timedelta(hours=10))
271 create_event(token2, None, h_id, "Event title 11", "Event content 11", timedelta(hours=11))
272 create_event(token2, None, h_id, "Event title 12", "Event content 12", timedelta(hours=12))
274 enforce_community_memberships()
276 create_place(token1, "Country 1, Region 1, Attraction", "Place content", "Somewhere in c1r1", 6)
277 create_place(token2, "Country 1, Region 1, City 1, Attraction 1", "Place content", "Somewhere in c1r1c1", 3)
278 create_place(token2, "Country 1, Region 1, City 1, Attraction 2", "Place content", "Somewhere in c1r1c1", 4)
279 create_place(token8, "Global, Attraction", "Place content", "Somewhere in w", 51.5)
280 create_place(token6, "Country 2, Region 1, Attraction", "Place content", "Somewhere in c2r1", 59)
282 refresh_materialized_views(None)
284 yield
287class TestCommunities:
288 @staticmethod
289 def test_GetCommunity(testing_communities):
290 with session_scope() as session:
291 user1_id, token1 = get_user_id_and_token(session, "user1")
292 user2_id, token2 = get_user_id_and_token(session, "user2")
293 user6_id, token6 = get_user_id_and_token(session, "user6")
294 w_id = get_community_id(session, "Global")
295 c1_id = get_community_id(session, "Country 1")
296 c1r1_id = get_community_id(session, "Country 1, Region 1")
297 c1r1c1_id = get_community_id(session, "Country 1, Region 1, City 1")
298 c2_id = get_community_id(session, "Country 2")
300 with communities_session(token2) as api:
301 res = api.GetCommunity(
302 communities_pb2.GetCommunityReq(
303 community_id=w_id,
304 )
305 )
306 assert res.name == "Global"
307 assert res.slug == "global"
308 assert res.description == "Description for Global"
309 assert len(res.parents) == 1
310 assert res.parents[0].HasField("community")
311 assert res.parents[0].community.community_id == w_id
312 assert res.parents[0].community.name == "Global"
313 assert res.parents[0].community.slug == "global"
314 assert res.parents[0].community.description == "Description for Global"
315 assert res.main_page.type == pages_pb2.PAGE_TYPE_MAIN_PAGE
316 assert res.main_page.slug == "main-page-for-the-global-community"
317 assert res.main_page.last_editor_user_id == user1_id
318 assert res.main_page.creator_user_id == user1_id
319 assert res.main_page.owner_community_id == w_id
320 assert res.main_page.title == "Main page for the Global community"
321 assert res.main_page.content == "There is nothing here yet..."
322 assert not res.main_page.can_edit
323 assert not res.main_page.can_moderate
324 assert res.main_page.editor_user_ids == [user1_id]
325 assert res.member
326 assert not res.admin
327 assert res.member_count == 8
328 assert res.admin_count == 3
330 res = api.GetCommunity(
331 communities_pb2.GetCommunityReq(
332 community_id=c1r1c1_id,
333 )
334 )
335 assert res.community_id == c1r1c1_id
336 assert res.name == "Country 1, Region 1, City 1"
337 assert res.slug == "country-1-region-1-city-1"
338 assert res.description == "Description for Country 1, Region 1, City 1"
339 assert len(res.parents) == 4
340 assert res.parents[0].HasField("community")
341 assert res.parents[0].community.community_id == w_id
342 assert res.parents[0].community.name == "Global"
343 assert res.parents[0].community.slug == "global"
344 assert res.parents[0].community.description == "Description for Global"
345 assert res.parents[1].HasField("community")
346 assert res.parents[1].community.community_id == c1_id
347 assert res.parents[1].community.name == "Country 1"
348 assert res.parents[1].community.slug == "country-1"
349 assert res.parents[1].community.description == "Description for Country 1"
350 assert res.parents[2].HasField("community")
351 assert res.parents[2].community.community_id == c1r1_id
352 assert res.parents[2].community.name == "Country 1, Region 1"
353 assert res.parents[2].community.slug == "country-1-region-1"
354 assert res.parents[2].community.description == "Description for Country 1, Region 1"
355 assert res.parents[3].HasField("community")
356 assert res.parents[3].community.community_id == c1r1c1_id
357 assert res.parents[3].community.name == "Country 1, Region 1, City 1"
358 assert res.parents[3].community.slug == "country-1-region-1-city-1"
359 assert res.parents[3].community.description == "Description for Country 1, Region 1, City 1"
360 assert res.main_page.type == pages_pb2.PAGE_TYPE_MAIN_PAGE
361 assert res.main_page.slug == "main-page-for-the-country-1-region-1-city-1-community"
362 assert res.main_page.last_editor_user_id == user2_id
363 assert res.main_page.creator_user_id == user2_id
364 assert res.main_page.owner_community_id == c1r1c1_id
365 assert res.main_page.title == "Main page for the Country 1, Region 1, City 1 community"
366 assert res.main_page.content == "There is nothing here yet..."
367 assert res.main_page.can_edit
368 assert res.main_page.can_moderate
369 assert res.main_page.editor_user_ids == [user2_id]
370 assert res.member
371 assert res.admin
372 assert res.member_count == 3
373 assert res.admin_count == 1
375 res = api.GetCommunity(
376 communities_pb2.GetCommunityReq(
377 community_id=c2_id,
378 )
379 )
380 assert res.community_id == c2_id
381 assert res.name == "Country 2"
382 assert res.slug == "country-2"
383 assert res.description == "Description for Country 2"
384 assert len(res.parents) == 2
385 assert res.parents[0].HasField("community")
386 assert res.parents[0].community.community_id == w_id
387 assert res.parents[0].community.name == "Global"
388 assert res.parents[0].community.slug == "global"
389 assert res.parents[0].community.description == "Description for Global"
390 assert res.parents[1].HasField("community")
391 assert res.parents[1].community.community_id == c2_id
392 assert res.parents[1].community.name == "Country 2"
393 assert res.parents[1].community.slug == "country-2"
394 assert res.parents[1].community.description == "Description for Country 2"
395 assert res.main_page.type == pages_pb2.PAGE_TYPE_MAIN_PAGE
396 assert res.main_page.slug == "main-page-for-the-country-2-community"
397 assert res.main_page.last_editor_user_id == user6_id
398 assert res.main_page.creator_user_id == user6_id
399 assert res.main_page.owner_community_id == c2_id
400 assert res.main_page.title == "Main page for the Country 2 community"
401 assert res.main_page.content == "There is nothing here yet..."
402 assert not res.main_page.can_edit
403 assert not res.main_page.can_moderate
404 assert res.main_page.editor_user_ids == [user6_id]
405 assert not res.member
406 assert not res.admin
407 assert res.member_count == 2
408 assert res.admin_count == 2
410 @staticmethod
411 def test_ListCommunities(testing_communities):
412 with session_scope() as session:
413 user1_id, token1 = get_user_id_and_token(session, "user1")
414 c1_id = get_community_id(session, "Country 1")
415 c1r1_id = get_community_id(session, "Country 1, Region 1")
416 c1r2_id = get_community_id(session, "Country 1, Region 2")
418 with communities_session(token1) as api:
419 res = api.ListCommunities(
420 communities_pb2.ListCommunitiesReq(
421 community_id=c1_id,
422 )
423 )
424 assert [c.community_id for c in res.communities] == [c1r1_id, c1r2_id]
426 @staticmethod
427 def test_ListCommunities_all(testing_communities):
428 with session_scope() as session:
429 user1_id, token1 = get_user_id_and_token(session, "user1")
430 w_id = get_community_id(session, "Global")
431 c1_id = get_community_id(session, "Country 1")
432 c1r1_id = get_community_id(session, "Country 1, Region 1")
433 c1r1c1_id = get_community_id(session, "Country 1, Region 1, City 1")
434 c1r1c2_id = get_community_id(session, "Country 1, Region 1, City 2")
435 c1r2_id = get_community_id(session, "Country 1, Region 2")
436 c1r2c1_id = get_community_id(session, "Country 1, Region 2, City 1")
437 c2_id = get_community_id(session, "Country 2")
438 c2r1_id = get_community_id(session, "Country 2, Region 1")
439 c2r1c1_id = get_community_id(session, "Country 2, Region 1, City 1")
441 # Fetch all communities ordered by name
442 with communities_session(token1) as api:
443 res = api.ListCommunities(
444 communities_pb2.ListCommunitiesReq(
445 page_size=5,
446 )
447 )
448 assert [c.community_id for c in res.communities] == [c1_id, c1r1_id, c1r1c1_id, c1r1c2_id, c1r2_id]
449 res = api.ListCommunities(
450 communities_pb2.ListCommunitiesReq(
451 page_size=2,
452 page_token=res.next_page_token,
453 )
454 )
455 assert [c.community_id for c in res.communities] == [c1r2c1_id, c2_id]
456 res = api.ListCommunities(
457 communities_pb2.ListCommunitiesReq(
458 page_size=5,
459 page_token=res.next_page_token,
460 )
461 )
462 assert [c.community_id for c in res.communities] == [c2r1_id, c2r1c1_id, w_id]
464 @staticmethod
465 def test_ListUserCommunities(testing_communities):
466 with session_scope() as session:
467 user2_id, token2 = get_user_id_and_token(session, "user2")
468 w_id = get_community_id(session, "Global")
469 c1_id = get_community_id(session, "Country 1")
470 c1r1_id = get_community_id(session, "Country 1, Region 1")
471 c1r1c1_id = get_community_id(session, "Country 1, Region 1, City 1")
472 c1r1c2_id = get_community_id(session, "Country 1, Region 1, City 2")
473 c1r2_id = get_community_id(session, "Country 1, Region 2")
474 c1r2c1_id = get_community_id(session, "Country 1, Region 2, City 1")
476 # Fetch user2's communities from user2's account
477 with communities_session(token2) as api:
478 res = api.ListUserCommunities(communities_pb2.ListUserCommunitiesReq())
479 assert [c.community_id for c in res.communities] == [
480 w_id,
481 c1_id,
482 c1r1_id,
483 c1r1c1_id,
484 c1r1c2_id,
485 c1r2_id,
486 c1r2c1_id,
487 ]
489 @staticmethod
490 def test_ListOtherUserCommunities(testing_communities):
491 with session_scope() as session:
492 user1_id, token1 = get_user_id_and_token(session, "user1")
493 user2_id, token2 = get_user_id_and_token(session, "user2")
494 w_id = get_community_id(session, "Global")
495 c1_id = get_community_id(session, "Country 1")
496 c1r1_id = get_community_id(session, "Country 1, Region 1")
497 c1r1c1_id = get_community_id(session, "Country 1, Region 1, City 1")
498 c1r1c2_id = get_community_id(session, "Country 1, Region 1, City 2")
499 c1r2_id = get_community_id(session, "Country 1, Region 2")
500 c1r2c1_id = get_community_id(session, "Country 1, Region 2, City 1")
502 # Fetch user2's communities from user1's account
503 with communities_session(token1) as api:
504 res = api.ListUserCommunities(communities_pb2.ListUserCommunitiesReq(user_id=user2_id))
505 assert [c.community_id for c in res.communities] == [
506 w_id,
507 c1_id,
508 c1r1_id,
509 c1r1c1_id,
510 c1r1c2_id,
511 c1r2_id,
512 c1r2c1_id,
513 ]
515 @staticmethod
516 def test_ListGroups(testing_communities):
517 with session_scope() as session:
518 user1_id, token1 = get_user_id_and_token(session, "user1")
519 user5_id, token5 = get_user_id_and_token(session, "user5")
520 w_id = get_community_id(session, "Global")
521 hitchhikers_id = get_group_id(session, "Hitchhikers")
522 c1r1_id = get_community_id(session, "Country 1, Region 1")
523 foodies_id = get_group_id(session, "Country 1, Region 1, Foodies")
524 skaters_id = get_group_id(session, "Country 1, Region 1, Skaters")
526 with communities_session(token1) as api:
527 res = api.ListGroups(
528 communities_pb2.ListGroupsReq(
529 community_id=c1r1_id,
530 )
531 )
532 assert [g.group_id for g in res.groups] == [foodies_id, skaters_id]
534 with communities_session(token5) as api:
535 res = api.ListGroups(
536 communities_pb2.ListGroupsReq(
537 community_id=w_id,
538 )
539 )
540 assert len(res.groups) == 1
541 assert res.groups[0].group_id == hitchhikers_id
543 @staticmethod
544 def test_ListAdmins(testing_communities):
545 with session_scope() as session:
546 user1_id, token1 = get_user_id_and_token(session, "user1")
547 user3_id, token3 = get_user_id_and_token(session, "user3")
548 user4_id, token4 = get_user_id_and_token(session, "user4")
549 user5_id, token5 = get_user_id_and_token(session, "user5")
550 user7_id, token7 = get_user_id_and_token(session, "user7")
551 w_id = get_community_id(session, "Global")
552 c1r1c2_id = get_community_id(session, "Country 1, Region 1, City 2")
554 with communities_session(token1) as api:
555 res = api.ListAdmins(
556 communities_pb2.ListAdminsReq(
557 community_id=w_id,
558 )
559 )
560 assert res.admin_user_ids == [user1_id, user3_id, user7_id]
562 res = api.ListAdmins(
563 communities_pb2.ListAdminsReq(
564 community_id=c1r1c2_id,
565 )
566 )
567 assert res.admin_user_ids == [user4_id, user5_id]
569 @staticmethod
570 def test_AddAdmin(testing_communities):
571 with session_scope() as session:
572 user4_id, token4 = get_user_id_and_token(session, "user4")
573 user5_id, _ = get_user_id_and_token(session, "user5")
574 user2_id, _ = get_user_id_and_token(session, "user2")
575 user8_id, token8 = get_user_id_and_token(session, "user8")
576 node_id = get_community_id(session, "Country 1, Region 1, City 2")
578 with communities_session(token8) as api:
579 with pytest.raises(grpc.RpcError) as err:
580 api.AddAdmin(communities_pb2.AddAdminReq(community_id=node_id, user_id=user2_id))
581 assert err.value.code() == grpc.StatusCode.FAILED_PRECONDITION
582 assert err.value.details() == "You're not allowed to moderate that community"
584 with communities_session(token4) as api:
585 res = api.ListAdmins(communities_pb2.ListAdminsReq(community_id=node_id))
586 assert res.admin_user_ids == [user4_id, user5_id]
588 with pytest.raises(grpc.RpcError) as err:
589 api.AddAdmin(communities_pb2.AddAdminReq(community_id=node_id, user_id=user8_id))
590 assert err.value.code() == grpc.StatusCode.FAILED_PRECONDITION
591 assert err.value.details() == "That user is not in the community."
593 with pytest.raises(grpc.RpcError) as err:
594 api.AddAdmin(communities_pb2.AddAdminReq(community_id=node_id, user_id=user5_id))
595 assert err.value.code() == grpc.StatusCode.FAILED_PRECONDITION
596 assert err.value.details() == "That user is already an admin."
598 api.AddAdmin(communities_pb2.AddAdminReq(community_id=node_id, user_id=user2_id))
599 res = api.ListAdmins(communities_pb2.ListAdminsReq(community_id=node_id))
600 assert res.admin_user_ids == [user2_id, user4_id, user5_id]
601 # Cleanup because database changes do not roll back
602 api.RemoveAdmin(communities_pb2.RemoveAdminReq(community_id=node_id, user_id=user2_id))
604 @staticmethod
605 def test_RemoveAdmin(testing_communities):
606 with session_scope() as session:
607 user4_id, token4 = get_user_id_and_token(session, "user4")
608 user5_id, _ = get_user_id_and_token(session, "user5")
609 user2_id, _ = get_user_id_and_token(session, "user2")
610 user8_id, token8 = get_user_id_and_token(session, "user8")
611 node_id = get_community_id(session, "Country 1, Region 1, City 2")
613 with communities_session(token8) as api:
614 with pytest.raises(grpc.RpcError) as err:
615 api.AddAdmin(communities_pb2.AddAdminReq(community_id=node_id, user_id=user2_id))
616 assert err.value.code() == grpc.StatusCode.FAILED_PRECONDITION
617 assert err.value.details() == "You're not allowed to moderate that community"
619 with communities_session(token4) as api:
620 res = api.ListAdmins(communities_pb2.ListAdminsReq(community_id=node_id))
621 assert res.admin_user_ids == [user4_id, user5_id]
623 with pytest.raises(grpc.RpcError) as err:
624 api.RemoveAdmin(communities_pb2.RemoveAdminReq(community_id=node_id, user_id=user8_id))
625 assert err.value.code() == grpc.StatusCode.FAILED_PRECONDITION
626 assert err.value.details() == "That user is not in the community."
628 with pytest.raises(grpc.RpcError) as err:
629 api.RemoveAdmin(communities_pb2.RemoveAdminReq(community_id=node_id, user_id=user2_id))
630 assert err.value.code() == grpc.StatusCode.FAILED_PRECONDITION
631 assert err.value.details() == "That user is not an admin."
633 api.RemoveAdmin(communities_pb2.RemoveAdminReq(community_id=node_id, user_id=user5_id))
634 res = api.ListAdmins(communities_pb2.ListAdminsReq(community_id=node_id))
635 assert res.admin_user_ids == [user4_id]
636 # Cleanup because database changes do not roll back
637 api.AddAdmin(communities_pb2.AddAdminReq(community_id=node_id, user_id=user5_id))
639 @staticmethod
640 def test_ListMembers(testing_communities):
641 with session_scope() as session:
642 user1_id, token1 = get_user_id_and_token(session, "user1")
643 user2_id, token2 = get_user_id_and_token(session, "user2")
644 user3_id, token3 = get_user_id_and_token(session, "user3")
645 user4_id, token4 = get_user_id_and_token(session, "user4")
646 user5_id, token5 = get_user_id_and_token(session, "user5")
647 user6_id, token6 = get_user_id_and_token(session, "user6")
648 user7_id, token7 = get_user_id_and_token(session, "user7")
649 user8_id, token8 = get_user_id_and_token(session, "user8")
650 w_id = get_community_id(session, "Global")
651 c1r1c2_id = get_community_id(session, "Country 1, Region 1, City 2")
653 with communities_session(token1) as api:
654 res = api.ListMembers(
655 communities_pb2.ListMembersReq(
656 community_id=w_id,
657 )
658 )
659 assert res.member_user_ids == [
660 user8_id,
661 user7_id,
662 user6_id,
663 user5_id,
664 user4_id,
665 user3_id,
666 user2_id,
667 user1_id,
668 ]
670 res = api.ListMembers(
671 communities_pb2.ListMembersReq(
672 community_id=c1r1c2_id,
673 )
674 )
675 assert res.member_user_ids == [user5_id, user4_id, user2_id]
677 @staticmethod
678 def test_ListNearbyUsers(testing_communities):
679 with session_scope() as session:
680 user1_id, token1 = get_user_id_and_token(session, "user1")
681 user2_id, token2 = get_user_id_and_token(session, "user2")
682 user3_id, token3 = get_user_id_and_token(session, "user3")
683 user4_id, token4 = get_user_id_and_token(session, "user4")
684 user5_id, token5 = get_user_id_and_token(session, "user5")
685 user6_id, token6 = get_user_id_and_token(session, "user6")
686 user7_id, token7 = get_user_id_and_token(session, "user7")
687 user8_id, token8 = get_user_id_and_token(session, "user8")
688 w_id = get_community_id(session, "Global")
689 c1r1c2_id = get_community_id(session, "Country 1, Region 1, City 2")
691 with communities_session(token1) as api:
692 res = api.ListNearbyUsers(
693 communities_pb2.ListNearbyUsersReq(
694 community_id=w_id,
695 )
696 )
697 assert res.nearby_user_ids == [
698 user1_id,
699 user2_id,
700 user3_id,
701 user4_id,
702 user5_id,
703 user6_id,
704 user7_id,
705 user8_id,
706 ]
708 res = api.ListNearbyUsers(
709 communities_pb2.ListNearbyUsersReq(
710 community_id=c1r1c2_id,
711 )
712 )
713 assert res.nearby_user_ids == [user4_id]
715 @staticmethod
716 def test_ListDiscussions(testing_communities):
717 with session_scope() as session:
718 user1_id, token1 = get_user_id_and_token(session, "user1")
719 w_id = get_community_id(session, "Global")
720 c1r1c2_id = get_community_id(session, "Country 1, Region 1, City 2")
722 with communities_session(token1) as api:
723 res = api.ListDiscussions(
724 communities_pb2.ListDiscussionsReq(
725 community_id=w_id,
726 page_size=3,
727 )
728 )
729 assert [d.title for d in res.discussions] == [
730 "Discussion title 6",
731 "Discussion title 5",
732 "Discussion title 4",
733 ]
734 for d in res.discussions:
735 assert d.thread.thread_id > 0
736 assert d.thread.num_responses == 0
738 res = api.ListDiscussions(
739 communities_pb2.ListDiscussionsReq(
740 community_id=w_id,
741 page_token=res.next_page_token,
742 page_size=2,
743 )
744 )
745 assert [d.title for d in res.discussions] == [
746 "Discussion title 3",
747 "Discussion title 2",
748 ]
749 for d in res.discussions:
750 assert d.thread.thread_id > 0
751 assert d.thread.num_responses == 0
753 res = api.ListDiscussions(
754 communities_pb2.ListDiscussionsReq(
755 community_id=w_id,
756 page_token=res.next_page_token,
757 page_size=2,
758 )
759 )
760 assert [d.title for d in res.discussions] == [
761 "Discussion title 1",
762 ]
763 for d in res.discussions:
764 assert d.thread.thread_id > 0
765 assert d.thread.num_responses == 0
767 res = api.ListDiscussions(
768 communities_pb2.ListDiscussionsReq(
769 community_id=c1r1c2_id,
770 )
771 )
772 assert [d.title for d in res.discussions] == [
773 "Discussion title 7",
774 ]
775 for d in res.discussions:
776 assert d.thread.thread_id > 0
777 assert d.thread.num_responses == 0
779 @staticmethod
780 def test_is_user_in_node_geography(testing_communities):
781 with session_scope() as session:
782 c1_id = get_community_id(session, "Country 1")
784 user1_id, _ = get_user_id_and_token(session, "user1")
785 user2_id, _ = get_user_id_and_token(session, "user2")
786 user3_id, _ = get_user_id_and_token(session, "user3")
787 user4_id, _ = get_user_id_and_token(session, "user4")
788 user5_id, _ = get_user_id_and_token(session, "user5")
790 # All these users should be in Country 1's geography
791 assert is_user_in_node_geography(session, user1_id, c1_id)
792 assert is_user_in_node_geography(session, user2_id, c1_id)
793 assert is_user_in_node_geography(session, user3_id, c1_id)
794 assert is_user_in_node_geography(session, user4_id, c1_id)
795 assert is_user_in_node_geography(session, user5_id, c1_id)
797 @staticmethod
798 def test_ListEvents(testing_communities):
799 with session_scope() as session:
800 user1_id, token1 = get_user_id_and_token(session, "user1")
801 c1_id = get_community_id(session, "Country 1")
803 with communities_session(token1) as api:
804 res = api.ListEvents(
805 communities_pb2.ListEventsReq(
806 community_id=c1_id,
807 page_size=3,
808 )
809 )
810 assert [d.title for d in res.events] == [
811 "Event title 1",
812 "Event title 2",
813 "Event title 3",
814 ]
816 res = api.ListEvents(
817 communities_pb2.ListEventsReq(
818 community_id=c1_id,
819 page_token=res.next_page_token,
820 page_size=2,
821 )
822 )
823 assert [d.title for d in res.events] == [
824 "Event title 4",
825 "Event title 5",
826 ]
828 res = api.ListEvents(
829 communities_pb2.ListEventsReq(
830 community_id=c1_id,
831 page_token=res.next_page_token,
832 page_size=2,
833 )
834 )
835 assert [d.title for d in res.events] == [
836 "Event title 6",
837 ]
838 assert not res.next_page_token
840 @staticmethod
841 def test_empty_query_aborts(testing_communities):
842 with session_scope() as session:
843 _, token = get_user_id_and_token(session, "user1")
845 with communities_session(token) as api:
846 with pytest.raises(grpc.RpcError) as err:
847 api.SearchCommunities(communities_pb2.SearchCommunitiesReq(query=" "))
848 assert err.value.code() == grpc.StatusCode.INVALID_ARGUMENT
849 assert err.value.details() == "Query must be at least 3 characters long."
851 @staticmethod
852 def test_min_length_lt_3_aborts(testing_communities):
853 """
854 len(query) < 3 → return INVALID_ARGUMENT: query_too_short
855 """
856 with session_scope() as session:
857 _, token = get_user_id_and_token(session, "user1")
859 with communities_session(token) as api:
860 with pytest.raises(grpc.RpcError) as err:
861 api.SearchCommunities(communities_pb2.SearchCommunitiesReq(query="zz", page_size=5))
862 assert err.value.code() == grpc.StatusCode.INVALID_ARGUMENT
863 assert err.value.details() == "Query must be at least 3 characters long."
865 @staticmethod
866 def test_typo_matches_existing_name(testing_communities):
867 """
868 Word_similarity should match a simple typo in community name.
869 """
870 with session_scope() as session:
871 _, token = get_user_id_and_token(session, "user1")
872 c1_id = get_community_id(session, "Country 1")
874 with communities_session(token) as api:
875 res = api.SearchCommunities(communities_pb2.SearchCommunitiesReq(query="Coutri 1", page_size=5))
876 ids = [c.community_id for c in res.communities]
877 assert c1_id in ids
879 @staticmethod
880 def test_word_similarity_matches_partial_word(testing_communities):
881 """
882 Query 'city' should match 'Country 1, Region 1, City 1'.
883 """
884 with session_scope() as session:
885 _, token = get_user_id_and_token(session, "user1")
886 city1_id = get_community_id(session, "Country 1, Region 1, City 1") # переименовал для ясности
888 with communities_session(token) as api:
889 res = api.SearchCommunities(communities_pb2.SearchCommunitiesReq(query="city", page_size=5))
890 ids = [c.community_id for c in res.communities]
891 assert city1_id in ids
893 @staticmethod
894 def test_results_sorted_by_similarity(testing_communities):
895 """
896 Results should be ordered by similarity score (best match first).
897 For query 'Country 1, Region', the full region name should rank higher
898 than deeper descendants like 'City 1'.
899 """
900 with session_scope() as session:
901 _, token = get_user_id_and_token(session, "user1")
902 region_id = get_community_id(session, "Country 1, Region 1")
903 city_id = get_community_id(session, "Country 1, Region 1, City 1")
905 with communities_session(token) as api:
906 res = api.SearchCommunities(communities_pb2.SearchCommunitiesReq(query="Country 1, Region", page_size=5))
907 ids = [c.community_id for c in res.communities]
909 assert region_id in ids
910 assert city_id in ids
911 assert ids.index(region_id) < ids.index(city_id)
913 @staticmethod
914 def test_no_results_returns_empty(testing_communities):
915 """
916 For a nonsense query that shouldn't meet the similarity threshold, return empty list.
917 """
918 with session_scope() as session:
919 _, token = get_user_id_and_token(session, "user1")
921 with communities_session(token) as api:
922 res = api.SearchCommunities(communities_pb2.SearchCommunitiesReq(query="qwertyuiopasdf", page_size=5))
923 assert res.communities == []
925 @staticmethod
926 def test_ListAllCommunities(testing_communities):
927 """
928 Test that ListAllCommunities returns all communities with proper hierarchy information.
929 """
930 with session_scope() as session:
931 user1_id, token1 = get_user_id_and_token(session, "user1")
932 user2_id, token2 = get_user_id_and_token(session, "user2")
933 user6_id, token6 = get_user_id_and_token(session, "user6")
934 w_id = get_community_id(session, "Global")
935 c1_id = get_community_id(session, "Country 1")
936 c1r1_id = get_community_id(session, "Country 1, Region 1")
937 c1r1c1_id = get_community_id(session, "Country 1, Region 1, City 1")
938 c1r1c2_id = get_community_id(session, "Country 1, Region 1, City 2")
939 c1r2_id = get_community_id(session, "Country 1, Region 2")
940 c1r2c1_id = get_community_id(session, "Country 1, Region 2, City 1")
941 c2_id = get_community_id(session, "Country 2")
942 c2r1_id = get_community_id(session, "Country 2, Region 1")
943 c2r1c1_id = get_community_id(session, "Country 2, Region 1, City 1")
945 # Test with user1 who is a member of multiple communities
946 with communities_session(token1) as api:
947 res = api.ListAllCommunities(communities_pb2.ListAllCommunitiesReq())
949 # Should return all 10 communities
950 assert len(res.communities) == 10
952 # Get all community IDs
953 community_ids = [c.community_id for c in res.communities]
954 assert set(community_ids) == {
955 w_id,
956 c1_id,
957 c1r1_id,
958 c1r1c1_id,
959 c1r1c2_id,
960 c1r2_id,
961 c1r2c1_id,
962 c2_id,
963 c2r1_id,
964 c2r1c1_id,
965 }
967 # Check that each community has the required fields
968 for community in res.communities:
969 assert community.community_id > 0
970 assert len(community.name) > 0
971 assert len(community.slug) > 0
972 assert community.member_count > 0
973 # member field should be a boolean
974 assert isinstance(community.member, bool)
975 # parents should be present for hierarchical ordering
976 assert len(community.parents) >= 1
977 # created timestamp should be present
978 assert community.HasField("created")
979 assert community.created.seconds > 0
981 # Find specific communities and verify their data
982 global_community = next(c for c in res.communities if c.community_id == w_id)
983 assert global_community.name == "Global"
984 assert global_community.slug == "global"
985 assert global_community.member # user1 is a member
986 assert global_community.member_count == 8
987 assert len(global_community.parents) == 1 # Only itself
989 c1r1c1_community = next(c for c in res.communities if c.community_id == c1r1c1_id)
990 assert c1r1c1_community.name == "Country 1, Region 1, City 1"
991 assert c1r1c1_community.slug == "country-1-region-1-city-1"
992 assert c1r1c1_community.member # user1 is a member
993 assert c1r1c1_community.member_count == 3
994 assert len(c1r1c1_community.parents) == 4 # Global, Country 1, Region 1, City 1
995 # Verify parent hierarchy
996 assert c1r1c1_community.parents[0].community.community_id == w_id
997 assert c1r1c1_community.parents[1].community.community_id == c1_id
998 assert c1r1c1_community.parents[2].community.community_id == c1r1_id
999 assert c1r1c1_community.parents[3].community.community_id == c1r1c1_id
1001 # Test with user6 who has different community memberships
1002 with communities_session(token6) as api:
1003 res = api.ListAllCommunities(communities_pb2.ListAllCommunitiesReq())
1005 # Should still return all 10 communities
1006 assert len(res.communities) == 10
1008 # Find Country 2 community - user6 should be a member
1009 c2_community = next(c for c in res.communities if c.community_id == c2_id)
1010 assert c2_community.member # user6 is a member
1011 assert c2_community.member_count == 2
1013 # Find Country 1 - user6 should NOT be a member
1014 c1_community = next(c for c in res.communities if c.community_id == c1_id)
1015 assert not c1_community.member # user6 is not a member
1017 # Global - user6 should be a member
1018 global_community = next(c for c in res.communities if c.community_id == w_id)
1019 assert global_community.member # user6 is a member
1022def test_JoinCommunity_and_LeaveCommunity(testing_communities):
1023 # these are separate as they mutate the database
1024 with session_scope() as session:
1025 # at x=1, inside c1 (country 1)
1026 user1_id, token1 = get_user_id_and_token(session, "user1")
1027 # at x=51, not inside c1
1028 user8_id, token8 = get_user_id_and_token(session, "user8")
1029 c1_id = get_community_id(session, "Country 1")
1031 with communities_session(token1) as api:
1032 assert api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c1_id)).member
1034 # user1 is already part of c1, cannot join
1035 with pytest.raises(grpc.RpcError) as e:
1036 res = api.JoinCommunity(
1037 communities_pb2.JoinCommunityReq(
1038 community_id=c1_id,
1039 )
1040 )
1041 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1042 assert e.value.details() == "You're already in that community."
1044 assert api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c1_id)).member
1046 # user1 is inside c1, cannot leave
1047 with pytest.raises(grpc.RpcError) as e:
1048 res = api.LeaveCommunity(
1049 communities_pb2.LeaveCommunityReq(
1050 community_id=c1_id,
1051 )
1052 )
1053 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1054 assert (
1055 e.value.details()
1056 == "Your location on your profile is within this community, so you cannot leave it. However, you can adjust your notifications in your account settings."
1057 )
1059 assert api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c1_id)).member
1061 with communities_session(token8) as api:
1062 assert not api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c1_id)).member
1064 # user8 is not in c1 yet, cannot leave
1065 with pytest.raises(grpc.RpcError) as e:
1066 res = api.LeaveCommunity(
1067 communities_pb2.LeaveCommunityReq(
1068 community_id=c1_id,
1069 )
1070 )
1071 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1072 assert e.value.details() == "You're not in that community."
1074 assert not api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c1_id)).member
1076 # user8 is not in c1 and not part, can join
1077 res = api.JoinCommunity(
1078 communities_pb2.JoinCommunityReq(
1079 community_id=c1_id,
1080 )
1081 )
1083 assert api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c1_id)).member
1085 # user8 is not in c1 and but now part, can't join again
1086 with pytest.raises(grpc.RpcError) as e:
1087 res = api.JoinCommunity(
1088 communities_pb2.JoinCommunityReq(
1089 community_id=c1_id,
1090 )
1091 )
1092 assert e.value.code() == grpc.StatusCode.FAILED_PRECONDITION
1093 assert e.value.details() == "You're already in that community."
1095 assert api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c1_id)).member
1097 # user8 is not in c1 yet, but part of it, can leave
1098 res = api.LeaveCommunity(
1099 communities_pb2.LeaveCommunityReq(
1100 community_id=c1_id,
1101 )
1102 )
1103 assert not api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c1_id)).member
1106def test_LeaveCommunity_regression(db):
1107 # See github issue #1444, repro:
1108 # 1. Join more than one community
1109 # 2. Leave one of them
1110 # 3. You are no longer in any community
1111 # admin
1112 user1, token1 = generate_user(username="user1", geom=create_1d_point(200), geom_radius=0.1)
1113 # joiner/leaver
1114 user2, token2 = generate_user(username="user2", geom=create_1d_point(201), geom_radius=0.1)
1116 with session_scope() as session:
1117 c0 = create_community(session, 0, 100, "Community 0", [user1], [], None)
1118 c1 = create_community(session, 0, 50, "Community 1", [user1], [], c0)
1119 c2 = create_community(session, 0, 10, "Community 2", [user1], [], c0)
1120 c0_id = c0.id
1121 c1_id = c1.id
1122 c2_id = c2.id
1124 enforce_community_memberships()
1126 with communities_session(token1) as api:
1127 assert api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c0_id)).member
1128 assert api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c1_id)).member
1129 assert api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c2_id)).member
1131 with communities_session(token2) as api:
1132 # first check we're not in any communities
1133 assert not api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c0_id)).member
1134 assert not api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c1_id)).member
1135 assert not api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c2_id)).member
1137 # join some communities
1138 api.JoinCommunity(communities_pb2.JoinCommunityReq(community_id=c1_id))
1139 api.JoinCommunity(communities_pb2.JoinCommunityReq(community_id=c2_id))
1141 # check memberships
1142 assert not api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c0_id)).member
1143 assert api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c1_id)).member
1144 assert api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c2_id)).member
1146 # leave just c2
1147 api.LeaveCommunity(communities_pb2.LeaveCommunityReq(community_id=c2_id))
1149 # check memberships
1150 assert not api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c0_id)).member
1151 assert api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c1_id)).member
1152 assert not api.GetCommunity(communities_pb2.GetCommunityReq(community_id=c2_id)).member
1155def test_enforce_community_memberships_for_user(testing_communities):
1156 """
1157 Make sure the user is added to the right communities on signup
1158 """
1159 with auth_api_session() as (auth_api, metadata_interceptor):
1160 res = auth_api.SignupFlow(
1161 auth_pb2.SignupFlowReq(
1162 basic=auth_pb2.SignupBasic(name="testing", email="email@couchers.org.invalid"),
1163 account=auth_pb2.SignupAccount(
1164 username="frodo",
1165 password="a very insecure password",
1166 birthdate="1970-01-01",
1167 gender="Bot",
1168 hosting_status=api_pb2.HOSTING_STATUS_CAN_HOST,
1169 city="Country 1, Region 1, City 2",
1170 # lat=8, lng=1 is equivalent to creating this coordinate with create_coordinate(8)
1171 lat=8,
1172 lng=1,
1173 radius=500,
1174 accept_tos=True,
1175 ),
1176 feedback=auth_pb2.ContributorForm(),
1177 accept_community_guidelines=wrappers_pb2.BoolValue(value=True),
1178 )
1179 )
1180 with session_scope() as session:
1181 email_token = (
1182 session.execute(select(SignupFlow).where(SignupFlow.flow_token == res.flow_token)).scalar_one().email_token
1183 )
1184 with auth_api_session() as (auth_api, metadata_interceptor):
1185 res = auth_api.SignupFlow(auth_pb2.SignupFlowReq(email_token=email_token))
1186 user_id = res.auth_res.user_id
1188 # now check the user is in the right communities
1189 with session_scope() as session:
1190 w_id = get_community_id(session, "Global")
1191 c1_id = get_community_id(session, "Country 1")
1192 c1r1_id = get_community_id(session, "Country 1, Region 1")
1193 c1r1c2_id = get_community_id(session, "Country 1, Region 1, City 2")
1195 token, _ = get_session_cookie_tokens(metadata_interceptor)
1197 with communities_session(token) as api:
1198 res = api.ListUserCommunities(communities_pb2.ListUserCommunitiesReq())
1199 assert [c.community_id for c in res.communities] == [w_id, c1_id, c1r1_id, c1r1c2_id]
1202# TODO: requires transferring of content
1204# def test_ListPlaces(db, testing_communities):
1205# pass
1207# def test_ListGuides(db, testing_communities):
1208# pass
1210# def test_ListEvents(db, testing_communities):
1211# pass