summary refs log tree commit diff
diff options
context:
space:
mode:
authorErik Johnston <erikj@jki.re>2017-08-21 16:51:56 +0100
committerGitHub <noreply@github.com>2017-08-21 16:51:56 +0100
commit2800983f3e81e3baa7dc45e4376a1f8a037097d7 (patch)
tree50070a4113aa75752802af7bbf0b9bb00fa877d0
parentMerge pull request #2426 from matrix-org/erikj/groups_fix_sync (diff)
parentUse BOOLEAN rather than TEXT type (diff)
downloadsynapse-2800983f3e81e3baa7dc45e4376a1f8a037097d7.tar.xz
Merge pull request #2410 from matrix-org/erikj/groups_publicise
Add ability to publicise group membership
-rw-r--r--synapse/federation/transport/client.py15
-rw-r--r--synapse/federation/transport/server.py17
-rw-r--r--synapse/handlers/groups_local.py50
-rw-r--r--synapse/rest/client/v2_alpha/groups.py83
-rw-r--r--synapse/storage/group_server.py31
-rw-r--r--synapse/storage/schema/delta/43/group_server.sql1
6 files changed, 197 insertions, 0 deletions
diff --git a/synapse/federation/transport/client.py b/synapse/federation/transport/client.py
index 073d3abb2a..ce68cc4937 100644
--- a/synapse/federation/transport/client.py
+++ b/synapse/federation/transport/client.py
@@ -812,3 +812,18 @@ class TransportLayerClient(object):
             args={"requester_user_id": requester_user_id},
             ignore_backoff=True,
         )
+
+    def bulk_get_publicised_groups(self, destination, user_ids):
+        """Get the groups a list of users are publicising
+        """
+
+        path = PREFIX + "/get_groups_publicised"
+
+        content = {"user_ids": user_ids}
+
+        return self.client.post_json(
+            destination=destination,
+            path=path,
+            data=content,
+            ignore_backoff=True,
+        )
diff --git a/synapse/federation/transport/server.py b/synapse/federation/transport/server.py
index e04750fd2a..b5f07c50bf 100644
--- a/synapse/federation/transport/server.py
+++ b/synapse/federation/transport/server.py
@@ -1050,6 +1050,22 @@ class FederationGroupsSummaryUsersServlet(BaseFederationServlet):
         defer.returnValue((200, resp))
 
 
+class FederationGroupsBulkPublicisedServlet(BaseFederationServlet):
+    """Get roles in a group
+    """
+    PATH = (
+        "/get_groups_publicised$"
+    )
+
+    @defer.inlineCallbacks
+    def on_POST(self, origin, content, query):
+        resp = yield self.handler.bulk_get_publicised_groups(
+            content["user_ids"], proxy=False,
+        )
+
+        defer.returnValue((200, resp))
+
+
 FEDERATION_SERVLET_CLASSES = (
     FederationSendServlet,
     FederationPullServlet,
@@ -1102,6 +1118,7 @@ GROUP_SERVER_SERVLET_CLASSES = (
 GROUP_LOCAL_SERVLET_CLASSES = (
     FederationGroupsLocalInviteServlet,
     FederationGroupsRemoveLocalUserServlet,
+    FederationGroupsBulkPublicisedServlet,
 )
 
 
diff --git a/synapse/handlers/groups_local.py b/synapse/handlers/groups_local.py
index b8b1e754c7..274fed9278 100644
--- a/synapse/handlers/groups_local.py
+++ b/synapse/handlers/groups_local.py
@@ -203,12 +203,16 @@ class GroupsLocalHandler(object):
                 user_id=user_id,
             )
 
+        # TODO: Check that the group is public and we're being added publically
+        is_publicised = content.get("publicise", False)
+
         token = yield self.store.register_user_group_membership(
             group_id, user_id,
             membership="join",
             is_admin=False,
             local_attestation=local_attestation,
             remote_attestation=remote_attestation,
+            is_publicised=is_publicised,
         )
         self.notifier.on_new_event(
             "groups_key", token, users=[user_id],
@@ -309,3 +313,49 @@ class GroupsLocalHandler(object):
     def get_joined_groups(self, user_id):
         group_ids = yield self.store.get_joined_groups(user_id)
         defer.returnValue({"groups": group_ids})
+
+    @defer.inlineCallbacks
+    def get_publicised_groups_for_user(self, user_id):
+        if self.hs.is_mine_id(user_id):
+            result = yield self.store.get_publicised_groups_for_user(user_id)
+            defer.returnValue({"groups": result})
+        else:
+            result = yield self.transport_client.get_publicised_groups_for_user(
+                get_domain_from_id(user_id), user_id
+            )
+            # TODO: Verify attestations
+            defer.returnValue(result)
+
+    @defer.inlineCallbacks
+    def bulk_get_publicised_groups(self, user_ids, proxy=True):
+        destinations = {}
+        local_users = set()
+
+        for user_id in user_ids:
+            if self.hs.is_mine_id(user_id):
+                local_users.add(user_id)
+            else:
+                destinations.setdefault(
+                    get_domain_from_id(user_id), set()
+                ).add(user_id)
+
+        if not proxy and destinations:
+            raise SynapseError(400, "Some user_ids are not local")
+
+        results = {}
+        failed_results = []
+        for destination, dest_user_ids in destinations.iteritems():
+            try:
+                r = yield self.transport_client.bulk_get_publicised_groups(
+                    destination, list(dest_user_ids),
+                )
+                results.update(r["users"])
+            except Exception:
+                failed_results.extend(dest_user_ids)
+
+        for uid in local_users:
+            results[uid] = yield self.store.get_publicised_groups_for_user(
+                uid
+            )
+
+        defer.returnValue({"users": results})
diff --git a/synapse/rest/client/v2_alpha/groups.py b/synapse/rest/client/v2_alpha/groups.py
index 009cd70737..b469058e9d 100644
--- a/synapse/rest/client/v2_alpha/groups.py
+++ b/synapse/rest/client/v2_alpha/groups.py
@@ -557,6 +557,86 @@ class GroupSelfAcceptInviteServlet(RestServlet):
         defer.returnValue((200, result))
 
 
+class GroupSelfUpdatePublicityServlet(RestServlet):
+    """Update whether we publicise a users membership of a group
+    """
+    PATTERNS = client_v2_patterns(
+        "/groups/(?P<group_id>[^/]*)/self/update_publicity$"
+    )
+
+    def __init__(self, hs):
+        super(GroupSelfUpdatePublicityServlet, self).__init__()
+        self.auth = hs.get_auth()
+        self.clock = hs.get_clock()
+        self.store = hs.get_datastore()
+
+    @defer.inlineCallbacks
+    def on_PUT(self, request, group_id):
+        requester = yield self.auth.get_user_by_req(request)
+        requester_user_id = requester.user.to_string()
+
+        content = parse_json_object_from_request(request)
+        publicise = content["publicise"]
+        yield self.store.update_group_publicity(
+            group_id, requester_user_id, publicise,
+        )
+
+        defer.returnValue((200, {}))
+
+
+class PublicisedGroupsForUserServlet(RestServlet):
+    """Get the list of groups a user is advertising
+    """
+    PATTERNS = client_v2_patterns(
+        "/publicised_groups/(?P<user_id>[^/]*)$"
+    )
+
+    def __init__(self, hs):
+        super(PublicisedGroupsForUserServlet, self).__init__()
+        self.auth = hs.get_auth()
+        self.clock = hs.get_clock()
+        self.store = hs.get_datastore()
+        self.groups_handler = hs.get_groups_local_handler()
+
+    @defer.inlineCallbacks
+    def on_GET(self, request, user_id):
+        yield self.auth.get_user_by_req(request)
+
+        result = yield self.groups_handler.get_publicised_groups_for_user(
+            user_id
+        )
+
+        defer.returnValue((200, result))
+
+
+class PublicisedGroupsForUsersServlet(RestServlet):
+    """Get the list of groups a user is advertising
+    """
+    PATTERNS = client_v2_patterns(
+        "/publicised_groups$"
+    )
+
+    def __init__(self, hs):
+        super(PublicisedGroupsForUsersServlet, self).__init__()
+        self.auth = hs.get_auth()
+        self.clock = hs.get_clock()
+        self.store = hs.get_datastore()
+        self.groups_handler = hs.get_groups_local_handler()
+
+    @defer.inlineCallbacks
+    def on_POST(self, request):
+        yield self.auth.get_user_by_req(request)
+
+        content = parse_json_object_from_request(request)
+        user_ids = content["user_ids"]
+
+        result = yield self.groups_handler.bulk_get_publicised_groups(
+            user_ids
+        )
+
+        defer.returnValue((200, result))
+
+
 class GroupsForUserServlet(RestServlet):
     """Get all groups the logged in user is joined to
     """
@@ -598,4 +678,7 @@ def register_servlets(hs, http_server):
     GroupSummaryRoomsCatServlet(hs).register(http_server)
     GroupRoleServlet(hs).register(http_server)
     GroupRolesServlet(hs).register(http_server)
+    GroupSelfUpdatePublicityServlet(hs).register(http_server)
     GroupSummaryUsersRoleServlet(hs).register(http_server)
+    PublicisedGroupsForUserServlet(hs).register(http_server)
+    PublicisedGroupsForUsersServlet(hs).register(http_server)
diff --git a/synapse/storage/group_server.py b/synapse/storage/group_server.py
index 792a57deb5..5433063507 100644
--- a/synapse/storage/group_server.py
+++ b/synapse/storage/group_server.py
@@ -835,11 +835,41 @@ class GroupServerStore(SQLBaseStore):
             desc="add_room_to_group",
         )
 
+    def get_publicised_groups_for_user(self, user_id):
+        """Get all groups a user is publicising
+        """
+        return self._simple_select_onecol(
+            table="local_group_membership",
+            keyvalues={
+                "user_id": user_id,
+                "membership": "join",
+                "is_publicised": True,
+            },
+            retcol="group_id",
+            desc="get_publicised_groups_for_user",
+        )
+
+    def update_group_publicity(self, group_id, user_id, publicise):
+        """Update whether the user is publicising their membership of the group
+        """
+        return self._simple_update_one(
+            table="local_group_membership",
+            keyvalues={
+                "group_id": group_id,
+                "user_id": user_id,
+            },
+            updatevalues={
+                "is_publicised": publicise,
+            },
+            desc="update_group_publicity"
+        )
+
     @defer.inlineCallbacks
     def register_user_group_membership(self, group_id, user_id, membership,
                                        is_admin=False, content={},
                                        local_attestation=None,
                                        remote_attestation=None,
+                                       is_publicised=False,
                                        ):
         """Registers that a local user is a member of a (local or remote) group.
 
@@ -873,6 +903,7 @@ class GroupServerStore(SQLBaseStore):
                     "user_id": user_id,
                     "is_admin": is_admin,
                     "membership": membership,
+                    "is_publicised": is_publicised,
                     "content": json.dumps(content),
                 },
             )
diff --git a/synapse/storage/schema/delta/43/group_server.sql b/synapse/storage/schema/delta/43/group_server.sql
index 92f3339c94..e74554381f 100644
--- a/synapse/storage/schema/delta/43/group_server.sql
+++ b/synapse/storage/schema/delta/43/group_server.sql
@@ -150,6 +150,7 @@ CREATE TABLE local_group_membership (
     user_id TEXT NOT NULL,
     is_admin BOOLEAN NOT NULL,
     membership TEXT NOT NULL,
+    is_publicised BOOLEAN NOT NULL,  -- if the user is publicising their membership
     content TEXT NOT NULL
 );