summary refs log tree commit diff
path: root/synapse
diff options
context:
space:
mode:
Diffstat (limited to 'synapse')
-rw-r--r--synapse/handlers/groups_local.py26
-rw-r--r--synapse/handlers/message.py2
-rw-r--r--synapse/rest/admin/__init__.py10
-rw-r--r--synapse/rest/admin/groups.py60
-rw-r--r--synapse/rest/admin/rooms.py39
5 files changed, 134 insertions, 3 deletions
diff --git a/synapse/handlers/groups_local.py b/synapse/handlers/groups_local.py
index df29edeb83..a2f16f77df 100644
--- a/synapse/handlers/groups_local.py
+++ b/synapse/handlers/groups_local.py
@@ -365,6 +365,32 @@ class GroupsLocalHandler(GroupsLocalWorkerHandler):
 
         return {}
 
+    async def force_join_user_to_group(self, group_id, user_id):
+        """Forces a user to join a group.
+        """
+        if not self.is_mine_id(group_id):
+            raise SynapseError(400, "Can only affect local groups")
+
+        if not self.is_mine_id(user_id):
+            raise SynapseError(400, "Can only affect local users")
+
+        # Bypass the group server to avoid business logic regarding whether or not
+        # the user can actually join.
+        await self.store.add_user_to_group(group_id, user_id)
+
+        token = await self.store.register_user_group_membership(
+            group_id,
+            user_id,
+            membership="join",
+            is_admin=False,
+            local_attestation=None,
+            remote_attestation=None,
+            is_publicised=False,
+        )
+        self.notifier.on_new_event("groups_key", token, users=[user_id])
+
+        return {}
+
     async def accept_invite(self, group_id, user_id, content):
         """Accept an invite to a group
         """
diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py
index 9dfeab09cd..d3f8dc550d 100644
--- a/synapse/handlers/message.py
+++ b/synapse/handlers/message.py
@@ -174,7 +174,7 @@ class MessageHandler:
                 raise NotFoundError("Can't find event for token %s" % (at_token,))
 
             visible_events = await filter_events_for_client(
-                self.storage, user_id, last_events, filter_send_to_client=False
+                self.storage, user_id, last_events, filter_send_to_client=False,
             )
 
             event = last_events[0]
diff --git a/synapse/rest/admin/__init__.py b/synapse/rest/admin/__init__.py
index 6f7dc06503..a20a459874 100644
--- a/synapse/rest/admin/__init__.py
+++ b/synapse/rest/admin/__init__.py
@@ -31,7 +31,11 @@ from synapse.rest.admin.event_reports import (
     EventReportDetailRestServlet,
     EventReportsRestServlet,
 )
-from synapse.rest.admin.groups import DeleteGroupAdminRestServlet
+from synapse.rest.admin.groups import (
+    DeleteGroupAdminRestServlet,
+    ForceJoinGroupAdminRestServlet,
+    UpdatePublicityGroupAdminRestServlet,
+)
 from synapse.rest.admin.media import ListMediaInRoom, register_servlets_for_media_repo
 from synapse.rest.admin.purge_room_servlet import PurgeRoomServlet
 from synapse.rest.admin.rooms import (
@@ -41,6 +45,7 @@ from synapse.rest.admin.rooms import (
     MakeRoomAdminRestServlet,
     RoomMembersRestServlet,
     RoomRestServlet,
+    RoomStateRestServlet,
     ShutdownRoomRestServlet,
 )
 from synapse.rest.admin.server_notice_servlet import SendServerNoticeServlet
@@ -209,6 +214,7 @@ def register_servlets(hs, http_server):
     """
     register_servlets_for_client_rest_resource(hs, http_server)
     ListRoomRestServlet(hs).register(http_server)
+    RoomStateRestServlet(hs).register(http_server)
     RoomRestServlet(hs).register(http_server)
     RoomMembersRestServlet(hs).register(http_server)
     DeleteRoomRestServlet(hs).register(http_server)
@@ -244,6 +250,8 @@ def register_servlets_for_client_rest_resource(hs, http_server):
     ShutdownRoomRestServlet(hs).register(http_server)
     UserRegisterServlet(hs).register(http_server)
     DeleteGroupAdminRestServlet(hs).register(http_server)
+    ForceJoinGroupAdminRestServlet(hs).register(http_server)
+    UpdatePublicityGroupAdminRestServlet(hs).register(http_server)
     AccountValidityRenewServlet(hs).register(http_server)
 
     # Load the media repo ones if we're using them. Otherwise load the servlets which
diff --git a/synapse/rest/admin/groups.py b/synapse/rest/admin/groups.py
index d0c86b204a..6af36e32b7 100644
--- a/synapse/rest/admin/groups.py
+++ b/synapse/rest/admin/groups.py
@@ -15,7 +15,11 @@
 import logging
 
 from synapse.api.errors import SynapseError
-from synapse.http.servlet import RestServlet
+from synapse.http.servlet import (
+    RestServlet,
+    assert_params_in_dict,
+    parse_json_object_from_request,
+)
 from synapse.rest.admin._base import admin_patterns, assert_user_is_admin
 
 logger = logging.getLogger(__name__)
@@ -41,3 +45,57 @@ class DeleteGroupAdminRestServlet(RestServlet):
 
         await self.group_server.delete_group(group_id, requester.user.to_string())
         return 200, {}
+
+
+class ForceJoinGroupAdminRestServlet(RestServlet):
+    """Allows a server admin to force-join a local user to a local group.
+    """
+
+    PATTERNS = admin_patterns("/group/(?P<group_id>[^/]*)/force_join$")
+
+    def __init__(self, hs):
+        self.groups_handler = hs.get_groups_local_handler()
+        self.is_mine_id = hs.is_mine_id
+        self.auth = hs.get_auth()
+
+    async def on_POST(self, request, group_id):
+        requester = await self.auth.get_user_by_req(request)
+        await assert_user_is_admin(self.auth, requester.user)
+
+        if not self.is_mine_id(group_id):
+            raise SynapseError(400, "Can only affect local groups")
+
+        body = parse_json_object_from_request(request, allow_empty_body=False)
+        assert_params_in_dict(body, ["user_id"])
+        target_user_id = body["user_id"]
+        await self.groups_handler.force_join_user_to_group(group_id, target_user_id)
+
+        return 200, {}
+
+
+class UpdatePublicityGroupAdminRestServlet(RestServlet):
+    """Allows a server admin to update a user's publicity (flair) for a given group.
+    """
+
+    PATTERNS = admin_patterns("/group/(?P<group_id>[^/]*)/update_publicity$")
+
+    def __init__(self, hs):
+        self.store = hs.get_datastore()
+        self.is_mine_id = hs.is_mine_id
+        self.auth = hs.get_auth()
+
+    async def on_POST(self, request, group_id):
+        requester = await self.auth.get_user_by_req(request)
+        await assert_user_is_admin(self.auth, requester.user)
+
+        body = parse_json_object_from_request(request, allow_empty_body=False)
+        assert_params_in_dict(body, ["user_id"])
+        target_user_id = body["user_id"]
+        if not self.is_mine_id(target_user_id):
+            raise SynapseError(400, "Can only affect local users")
+
+        # Logic copied from `/self/update_publicity` endpoint.
+        publicise = body["publicise"]
+        await self.store.update_group_publicity(group_id, target_user_id, publicise)
+
+        return 200, {}
diff --git a/synapse/rest/admin/rooms.py b/synapse/rest/admin/rooms.py
index ab7cc9102a..d903129dd2 100644
--- a/synapse/rest/admin/rooms.py
+++ b/synapse/rest/admin/rooms.py
@@ -292,6 +292,45 @@ class RoomMembersRestServlet(RestServlet):
         return 200, ret
 
 
+class RoomStateRestServlet(RestServlet):
+    """
+    Get full state within a room.
+    """
+
+    PATTERNS = admin_patterns("/rooms/(?P<room_id>[^/]+)/state")
+
+    def __init__(self, hs: "HomeServer"):
+        self.hs = hs
+        self.auth = hs.get_auth()
+        self.store = hs.get_datastore()
+        self.clock = hs.get_clock()
+        self._event_serializer = hs.get_event_client_serializer()
+
+    async def on_GET(
+        self, request: SynapseRequest, room_id: str
+    ) -> Tuple[int, JsonDict]:
+        requester = await self.auth.get_user_by_req(request)
+        await assert_user_is_admin(self.auth, requester.user)
+
+        ret = await self.store.get_room(room_id)
+        if not ret:
+            raise NotFoundError("Room not found")
+
+        event_ids = await self.store.get_current_state_ids(room_id)
+        events = await self.store.get_events(event_ids.values())
+        now = self.clock.time_msec()
+        room_state = await self._event_serializer.serialize_events(
+            events.values(),
+            now,
+            # We don't bother bundling aggregations in when asked for state
+            # events, as clients won't use them.
+            bundle_aggregations=False,
+        )
+        ret = {"state": room_state}
+
+        return 200, ret
+
+
 class JoinRoomAliasServlet(RestServlet):
 
     PATTERNS = admin_patterns("/join/(?P<room_identifier>[^/]*)")