def create_community(session, interval_lb, interval_ub, name, admins, extra_members, parent): node = Node( geom=to_multi(create_1d_polygon(interval_lb, interval_ub)), parent_node=parent, ) session.add(node) cluster = Cluster( name=f"{name}", description=f"Description for {name}", parent_node=node, is_official_cluster=True, ) session.add(cluster) main_page = Page( parent_node=cluster.parent_node, creator_user_id=admins[0].id, owner_cluster=cluster, type=PageType.main_page, thread=Thread(), ) session.add(main_page) page_version = PageVersion( page=main_page, editor_user_id=admins[0].id, title=f"Main page for the {name} community", content="There is nothing here yet...", ) session.add(page_version) for admin in admins: cluster.cluster_subscriptions.append( ClusterSubscription( user_id=admin.id, role=ClusterRole.admin, )) for member in extra_members: cluster.cluster_subscriptions.append( ClusterSubscription( user_id=member.id, role=ClusterRole.member, )) session.commit() # other members will be added by enforce_community_memberships() return node
def test_node_constraints(db): # check we can't have two official clusters for a given node with pytest.raises(IntegrityError) as e: with session_scope() as session: node = Node(geom=to_multi(create_1d_polygon(0, 2))) session.add(node) cluster1 = Cluster( name=f"Testing community, cluster 1", description=f"Testing community description", parent_node=node, is_official_cluster=True, ) session.add(cluster1) cluster2 = Cluster( name=f"Testing community, cluster 2", description=f"Testing community description", parent_node=node, is_official_cluster=True, ) session.add(cluster2) assert "violates unique constraint" in str(e.value) assert "ix_clusters_owner_parent_node_id_is_official_cluster" in str( e.value)
def test_page_constraints(db): user, token = generate_user() with session_scope() as session: c_id = create_community(session, 0, 2, "Root node", [user], [], None).id # check we can't create a page without an owner with pytest.raises(IntegrityError) as e: with session_scope() as session: page = Page( parent_node_id=c_id, # note no owner creator_user_id=user.id, type=PageType.guide, thread=Thread(), ) session.add(page) session.add( PageVersion( page=page, editor_user_id=user.id, title=f"Title", content="Content", )) assert "violates check constraint" in str(e.value) assert "one_owner" in str(e.value) with session_scope() as session: node = Node(geom=to_multi( create_polygon_lat_lng([[0, 0], [0, 2], [2, 2], [2, 0], [0, 0]]))) session.add(node) cluster = Cluster( name=f"Testing Community", description=f"Description for testing community", parent_node=node, ) session.add(cluster) session.flush() cluster_parent_id = cluster.parent_node_id cluster_id = cluster.id # check we can't create a page with two owners with pytest.raises(IntegrityError) as e: with session_scope() as session: page = Page( parent_node_id=cluster_parent_id, creator_user_id=user.id, owner_cluster_id=cluster_id, owner_user_id=user.id, type=PageType.guide, thread=Thread(), ) session.add(page) session.add( PageVersion( page=page, editor_user_id=user.id, title=f"Title", content="Content", )) assert "violates check constraint" in str(e.value) assert "one_owner" in str(e.value) # main page must be owned by the right cluster with pytest.raises(IntegrityError) as e: with session_scope() as session: main_page = Page( parent_node_id=cluster_parent_id, # note owner is not cluster creator_user_id=user.id, owner_user_id=user.id, type=PageType.main_page, thread=Thread(), ) session.add(main_page) session.add( PageVersion( page=main_page, editor_user_id=user.id, title=f"Main page for the testing community", content="Empty.", )) assert "violates check constraint" in str(e.value) assert "main_page_owned_by_cluster" in str(e.value) # can only have one main page with pytest.raises(IntegrityError) as e: with session_scope() as session: main_page1 = Page( parent_node_id=cluster_parent_id, creator_user_id=user.id, owner_cluster_id=cluster_id, type=PageType.main_page, thread=Thread(), ) session.add(main_page1) session.add( PageVersion( page=main_page1, editor_user_id=user.id, title=f"Main page 1 for the testing community", content="Empty.", )) main_page2 = Page( parent_node_id=cluster_parent_id, creator_user_id=user.id, owner_cluster_id=cluster_id, type=PageType.main_page, thread=Thread(), ) session.add(main_page2) session.add( PageVersion( page=main_page2, editor_user_id=user.id, title=f"Main page 2 for the testing community", content="Empty.", )) assert "violates unique constraint" in str(e.value) assert "ix_pages_owner_cluster_id_type" in str(e.value)
def test_page_transfer(db): # transfers the pages user1, token1 = generate_user() # admin of the community/group user2, token2 = generate_user() # member of the community/group, shouldn't ever have edit access to anything user3, token3 = generate_user() with session_scope() as session: # create a community node = Node(geom=to_multi( create_polygon_lat_lng([[0, 0], [0, 2], [2, 2], [2, 0], [0, 0]]))) session.add(node) community_cluster = Cluster( name=f"Testing Community", description=f"Description for testing community", parent_node=node, is_official_cluster=True, ) session.add(community_cluster) main_page = Page( parent_node=community_cluster.parent_node, creator_user_id=user2.id, owner_cluster=community_cluster, type=PageType.main_page, thread=Thread(), ) session.add(main_page) session.add( PageVersion( page=main_page, editor_user_id=user2.id, title=f"Main page for the testing community", content="Empty.", )) community_cluster.cluster_subscriptions.append( ClusterSubscription( user_id=user2.id, role=ClusterRole.admin, )) community_cluster.cluster_subscriptions.append( ClusterSubscription( user_id=user3.id, role=ClusterRole.member, )) # create a group group_cluster = Cluster( name=f"Testing Group", description=f"Description for testing group", parent_node=node, ) session.add(group_cluster) main_page = Page( parent_node=group_cluster.parent_node, creator_user_id=user2.id, owner_cluster=group_cluster, type=PageType.main_page, thread=Thread(), ) session.add(main_page) session.add( PageVersion( page=main_page, editor_user_id=user2.id, title=f"Main page for the testing community", content="Empty.", )) group_cluster.cluster_subscriptions.append( ClusterSubscription( user_id=user2.id, role=ClusterRole.admin, )) group_cluster.cluster_subscriptions.append( ClusterSubscription( user_id=user3.id, role=ClusterRole.member, )) session.flush() community_id = node.id community_cluster_id = community_cluster.id group_id = group_cluster.id with pages_session(token1) as api: create_page_req = pages_pb2.CreatePlaceReq( title="title", content="content", address="address", location=pages_pb2.Coordinate( lat=1, lng=1, ), ) # transfer should work fine to a community page1 = api.CreatePlace(create_page_req) assert page1.owner_user_id == user1.id assert page1.can_edit assert not page1.can_moderate with pages_session(token2) as api: assert not api.GetPage( pages_pb2.GetPageReq(page_id=page1.page_id)).can_edit assert api.GetPage( pages_pb2.GetPageReq(page_id=page1.page_id)).can_moderate with pages_session(token3) as api: assert not api.GetPage( pages_pb2.GetPageReq(page_id=page1.page_id)).can_edit assert not api.GetPage( pages_pb2.GetPageReq(page_id=page1.page_id)).can_moderate with pages_session(token1) as api: page1 = api.TransferPage( pages_pb2.TransferPageReq( page_id=page1.page_id, new_owner_community_id=community_id, )) assert page1.owner_community_id == community_id assert not page1.can_edit assert not page1.can_moderate with pages_session(token2) as api: assert api.GetPage( pages_pb2.GetPageReq(page_id=page1.page_id)).can_edit assert api.GetPage( pages_pb2.GetPageReq(page_id=page1.page_id)).can_moderate with pages_session(token3) as api: assert not api.GetPage( pages_pb2.GetPageReq(page_id=page1.page_id)).can_edit assert not api.GetPage( pages_pb2.GetPageReq(page_id=page1.page_id)).can_moderate with pages_session(token1) as api: # now we're no longer the owner, can't transfer page1 = api.GetPage(pages_pb2.GetPageReq(page_id=page1.page_id)) with pytest.raises(grpc.RpcError) as e: api.TransferPage( pages_pb2.TransferPageReq( page_id=page1.page_id, new_owner_group_id=group_id, )) assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED assert e.value.details() == errors.PAGE_TRANSFER_PERMISSION_DENIED page1 = api.GetPage(pages_pb2.GetPageReq(page_id=page1.page_id)) assert page1.owner_community_id == community_id assert not page1.can_edit assert not page1.can_moderate with pages_session(token2) as api: assert api.GetPage( pages_pb2.GetPageReq(page_id=page1.page_id)).can_edit assert api.GetPage( pages_pb2.GetPageReq(page_id=page1.page_id)).can_moderate with pages_session(token3) as api: assert not api.GetPage( pages_pb2.GetPageReq(page_id=page1.page_id)).can_edit assert not api.GetPage( pages_pb2.GetPageReq(page_id=page1.page_id)).can_moderate with pages_session(token1) as api: # try a new page, just for fun page2 = api.CreatePlace(create_page_req) assert page2.owner_user_id == user1.id page2 = api.TransferPage( pages_pb2.TransferPageReq( page_id=page2.page_id, new_owner_community_id=community_id, )) assert page2.owner_community_id == community_id with pages_session(token2) as api: assert api.GetPage( pages_pb2.GetPageReq(page_id=page2.page_id)).can_edit assert api.GetPage( pages_pb2.GetPageReq(page_id=page2.page_id)).can_moderate with pages_session(token3) as api: assert not api.GetPage( pages_pb2.GetPageReq(page_id=page2.page_id)).can_edit assert not api.GetPage( pages_pb2.GetPageReq(page_id=page2.page_id)).can_moderate with pages_session(token1) as api: # can't transfer a page to an official cluster, only through community page3 = api.CreatePlace(create_page_req) assert page3.owner_user_id == user1.id with pytest.raises(grpc.RpcError) as e: api.TransferPage( pages_pb2.TransferPageReq( page_id=page3.page_id, new_owner_community_id=community_cluster_id, )) assert e.value.code() == grpc.StatusCode.NOT_FOUND assert e.value.details() == errors.GROUP_OR_COMMUNITY_NOT_FOUND page3 = api.GetPage(pages_pb2.GetPageReq(page_id=page3.page_id)) assert page3.owner_user_id == user1.id # can transfer to group page4 = api.CreatePlace(create_page_req) assert page4.owner_user_id == user1.id assert page4.can_edit assert not page4.can_moderate with pages_session(token2) as api: assert not api.GetPage( pages_pb2.GetPageReq(page_id=page4.page_id)).can_edit assert api.GetPage( pages_pb2.GetPageReq(page_id=page4.page_id)).can_moderate with pages_session(token3) as api: assert not api.GetPage( pages_pb2.GetPageReq(page_id=page4.page_id)).can_edit assert not api.GetPage( pages_pb2.GetPageReq(page_id=page4.page_id)).can_moderate with pages_session(token1) as api: page4 = api.TransferPage( pages_pb2.TransferPageReq( page_id=page4.page_id, new_owner_group_id=group_id, )) assert page4.owner_group_id == group_id assert not page4.can_edit assert not page4.can_moderate with pages_session(token2) as api: assert api.GetPage( pages_pb2.GetPageReq(page_id=page4.page_id)).can_edit assert api.GetPage( pages_pb2.GetPageReq(page_id=page4.page_id)).can_moderate with pages_session(token3) as api: assert not api.GetPage( pages_pb2.GetPageReq(page_id=page4.page_id)).can_edit assert not api.GetPage( pages_pb2.GetPageReq(page_id=page4.page_id)).can_moderate with pages_session(token1) as api: # now we're no longer the owner, can't transfer with pytest.raises(grpc.RpcError) as e: api.TransferPage( pages_pb2.TransferPageReq( page_id=page4.page_id, new_owner_community_id=community_id, )) assert e.value.code() == grpc.StatusCode.PERMISSION_DENIED assert e.value.details() == errors.PAGE_TRANSFER_PERMISSION_DENIED page4 = api.GetPage(pages_pb2.GetPageReq(page_id=page4.page_id)) assert page4.owner_group_id == group_id
def add_dummy_communities(): try: logger.info(f"Adding dummy communities") with session_scope() as session: if session.query(Node).count() > 0: logger.info("Nodes not empty, not adding dummy communities") return with open("src/data/dummy_communities.json", "r") as file: data = json.loads(file.read()) for community in data["communities"]: geom = None if "coordinates" in community: geom = create_polygon_lng_lat(community["coordinates"]) elif "osm_id" in community: with open(f"src/data/osm/{community['osm_id']}.geojson" ) as f: geojson = json.loads(f.read()) # pick the first feature geom = geojson_to_geom(geojson["features"][0]["geometry"]) if "geom_simplify" in community: geom = func.ST_Simplify(geom, community["geom_simplify"], True) else: ValueError("No geom or osm_id specified for node") name = community["name"] admins = session.query(User).filter( User.username.in_(community["admins"])).all() members = session.query(User).filter( User.username.in_(community["members"])).all() parent_name = community["parent"] if parent_name: parent_node = (session.query(Node).join( Cluster, Cluster.parent_node_id == Node.id).filter( Cluster.is_official_cluster).filter( Cluster.name == community["parent"]).one()) node = Node( geom=to_multi(geom), parent_node=parent_node if parent_name else None, ) session.add(node) cluster = Cluster( name=f"{name}", description=f"Description for {name}", parent_node=node, is_official_cluster=True, ) session.add(cluster) main_page = Page( parent_node=node, creator_user=admins[0], owner_cluster=cluster, type=PageType.main_page, thread=Thread(), ) session.add(main_page) page_version = PageVersion( page=main_page, editor_user=admins[0], title=f"Main page for the {name} community", content="There is nothing here yet...", ) session.add(page_version) for admin in admins: cluster.cluster_subscriptions.append( ClusterSubscription( user=admin, role=ClusterRole.admin, )) for member in members: cluster.cluster_subscriptions.append( ClusterSubscription( user=member, role=ClusterRole.member, )) for group in data["groups"]: name = group["name"] admins = session.query(User).filter( User.username.in_(group["admins"])).all() members = session.query(User).filter( User.username.in_(group["members"])).all() parent_node = (session.query(Node).join( Cluster, Cluster.parent_node_id == Node.id).filter( Cluster.is_official_cluster).filter( Cluster.name == group["parent"]).one()) cluster = Cluster( name=f"{name}", description=f"Description for the group {name}", parent_node=parent_node, ) session.add(cluster) main_page = Page( parent_node=cluster.parent_node, creator_user=admins[0], owner_cluster=cluster, type=PageType.main_page, thread=Thread(), ) session.add(main_page) page_version = PageVersion( page=main_page, editor_user=admins[0], title=f"Main page for the {name} group", content="There is nothing here yet...", ) session.add(page_version) for admin in admins: cluster.cluster_subscriptions.append( ClusterSubscription( user=admin, role=ClusterRole.admin, )) for member in members: cluster.cluster_subscriptions.append( ClusterSubscription( user=member, role=ClusterRole.member, )) for place in data["places"]: owner_cluster = session.query(Cluster).filter( Cluster.name == place["owner"]).one() creator = session.query(User).filter( User.username == place["creator"]).one() page = Page( parent_node=owner_cluster.parent_node, creator_user=creator, owner_cluster=owner_cluster, type=PageType.place, thread=Thread(), ) session.add(page) page_version = PageVersion( page=page, editor_user=creator, title=place["title"], content=place["content"], address=place["address"], geom=create_coordinate(place["coordinate"][1], place["coordinate"][0]), ) session.add(page_version) for guide in data["guides"]: owner_cluster = session.query(Cluster).filter( Cluster.name == guide["owner"]).one() creator = session.query(User).filter( User.username == guide["creator"]).one() page = Page( parent_node=owner_cluster.parent_node, creator_user=creator, owner_cluster=owner_cluster, type=PageType.guide, thread=Thread(), ) session.add(page) page_version = PageVersion( page=page, editor_user=creator, title=guide["title"], content=guide["content"], geom=create_coordinate(guide["coordinate"][1], guide["coordinate"][0]) if "coordinate" in guide else None, ) session.add(page_version) except IntegrityError: logger.error( "Failed to insert dummy communities, are they already inserted?")
def create_node(session, geom, parent_node_id): node = Node(geom=from_shape(geom), parent_node_id=parent_node_id) session.add(node) session.flush() return node
def test_create_and_get_discussion(db): generate_user() user, token = generate_user() generate_user() generate_user() with session_scope() as session: node = Node(geom=to_multi( create_polygon_lat_lng([[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]))) session.add(node) community_cluster = Cluster( name=f"Testing Community", description=f"Description for testing community", parent_node=node, is_official_cluster=True, ) session.add(community_cluster) main_page = Page( parent_node=community_cluster.parent_node, creator_user_id=user.id, owner_cluster=community_cluster, type=PageType.main_page, thread=Thread(), ) session.add(main_page) session.add( PageVersion( page=main_page, editor_user_id=user.id, title=f"Main page for the testing community", content="Empty.", )) # create a group group_cluster = Cluster( name=f"Testing Group", description=f"Description for testing group", parent_node=node, ) session.add(group_cluster) main_page = Page( parent_node=group_cluster.parent_node, creator_user_id=user.id, owner_cluster=group_cluster, type=PageType.main_page, thread=Thread(), ) session.add(main_page) session.add( PageVersion( page=main_page, editor_user_id=user.id, title=f"Main page for the testing community", content="Empty.", )) session.flush() community_id = node.id community_cluster_id = community_cluster.id group_id = group_cluster.id with discussions_session(token) as api: time_before_create = now() res = api.CreateDiscussion( discussions_pb2.CreateDiscussionReq( title="dummy title", content="dummy content", owner_community_id=community_id, )) time_after_create = now() assert res.title == "dummy title" assert res.content == "dummy content" assert res.slug == "dummy-title" assert time_before_create < to_aware_datetime( res.created) < time_after_create assert res.creator_user_id == user.id assert res.owner_community_id == community_id discussion_id = res.discussion_id with discussions_session(token) as api: res = api.GetDiscussion( discussions_pb2.GetDiscussionReq(discussion_id=discussion_id, )) assert res.title == "dummy title" assert res.content == "dummy content" assert res.slug == "dummy-title" assert time_before_create < to_aware_datetime( res.created) < time_after_create assert res.creator_user_id == user.id assert res.owner_community_id == community_id with discussions_session(token) as api: time_before_create = now() res = api.CreateDiscussion( discussions_pb2.CreateDiscussionReq( title="dummy title", content="dummy content", owner_group_id=group_id, )) time_after_create = now() assert res.title == "dummy title" assert res.content == "dummy content" assert res.slug == "dummy-title" assert time_before_create < to_aware_datetime( res.created) < time_after_create assert res.creator_user_id == user.id assert res.owner_group_id == group_id discussion_id = res.discussion_id with discussions_session(token) as api: res = api.GetDiscussion( discussions_pb2.GetDiscussionReq(discussion_id=discussion_id, )) assert res.title == "dummy title" assert res.content == "dummy content" assert res.slug == "dummy-title" assert time_before_create < to_aware_datetime( res.created) < time_after_create assert res.creator_user_id == user.id assert res.owner_group_id == group_id