diff options
author | Travis Ralston <travpc@gmail.com> | 2021-01-21 12:35:05 -0700 |
---|---|---|
committer | Travis Ralston <travpc@gmail.com> | 2021-01-21 12:35:05 -0700 |
commit | f7a03e86e0f99724acd28963e7600f13b487ce19 (patch) | |
tree | 7a0846bdf1d8b4b9526262eccd885e99fdb5e213 | |
parent | Merge branch 'travis/fosdem/admin-api-groups' into travis/fosdem/hotfixes (diff) | |
parent | Get the right requester object (diff) | |
download | synapse-f7a03e86e0f99724acd28963e7600f13b487ce19.tar.xz |
Merge branch 'travis/fosdem/admin-api-room-state' into travis/fosdem/hotfixes
-rw-r--r-- | changelog.d/9168.feature | 1 | ||||
-rw-r--r-- | docs/admin_api/rooms.md | 30 | ||||
-rw-r--r-- | synapse/handlers/message.py | 13 | ||||
-rw-r--r-- | synapse/rest/admin/__init__.py | 2 | ||||
-rw-r--r-- | synapse/rest/admin/rooms.py | 33 | ||||
-rw-r--r-- | tests/rest/admin/test_room.py | 15 |
6 files changed, 90 insertions, 4 deletions
diff --git a/changelog.d/9168.feature b/changelog.d/9168.feature new file mode 100644 index 0000000000..8be1950eee --- /dev/null +++ b/changelog.d/9168.feature @@ -0,0 +1 @@ +Add an admin API for retrieving the current room state of a room. \ No newline at end of file diff --git a/docs/admin_api/rooms.md b/docs/admin_api/rooms.md index 9e560003a9..d68003853b 100644 --- a/docs/admin_api/rooms.md +++ b/docs/admin_api/rooms.md @@ -367,6 +367,36 @@ Response: } ``` +# Room State API + +The Room State admin API allows server admins to get a list of all state events in a room. + +The response includes the following fields: + +* `state` - The current state of the room at the time of request. + +## Usage + +A standard request: + +``` +GET /_synapse/admin/v1/rooms/<room_id>/state + +{} +``` + +Response: + +```json +{ + "state": [ + {"type": "m.room.create", "state_key": "", "etc": true}, + {"type": "m.room.power_levels", "state_key": "", "etc": true}, + {"type": "m.room.name", "state_key": "", "etc": true} + ] +} +``` + # Delete Room API The Delete Room admin API allows server admins to remove rooms from server diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py index 9dfeab09cd..457491b75d 100644 --- a/synapse/handlers/message.py +++ b/synapse/handlers/message.py @@ -137,6 +137,7 @@ class MessageHandler: state_filter: StateFilter = StateFilter.all(), at_token: Optional[StreamToken] = None, is_guest: bool = False, + is_admin: bool = False, ) -> List[dict]: """Retrieve all state events for a given room. If the user is joined to the room then return the current state. If the user has @@ -153,6 +154,7 @@ class MessageHandler: stream token, we raise a 403 SynapseError. If None, returns the current state based on the current_state_events table. is_guest: whether this user is a guest + is_admin: whether this user is making the request as a server admin. Returns: A list of dicts representing state events. [{}, {}, {}] Raises: @@ -173,9 +175,12 @@ class MessageHandler: if not last_events: 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 - ) + if is_admin: + visible_events = last_events + else: + visible_events = await filter_events_for_client( + self.storage, user_id, last_events, filter_send_to_client=False, + ) event = last_events[0] if visible_events: @@ -197,7 +202,7 @@ class MessageHandler: room_id, user_id, allow_departed_users=True ) - if membership == Membership.JOIN: + if membership == Membership.JOIN or is_admin: state_ids = await self.store.get_filtered_current_state_ids( room_id, state_filter=state_filter ) diff --git a/synapse/rest/admin/__init__.py b/synapse/rest/admin/__init__.py index b7121c0c26..a20a459874 100644 --- a/synapse/rest/admin/__init__.py +++ b/synapse/rest/admin/__init__.py @@ -45,6 +45,7 @@ from synapse.rest.admin.rooms import ( MakeRoomAdminRestServlet, RoomMembersRestServlet, RoomRestServlet, + RoomStateRestServlet, ShutdownRoomRestServlet, ) from synapse.rest.admin.server_notice_servlet import SendServerNoticeServlet @@ -213,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) diff --git a/synapse/rest/admin/rooms.py b/synapse/rest/admin/rooms.py index ab7cc9102a..1d5f6c1807 100644 --- a/synapse/rest/admin/rooms.py +++ b/synapse/rest/admin/rooms.py @@ -292,6 +292,39 @@ 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.message_handler = hs.get_message_handler() + + 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") + + room_state = await self.message_handler.get_state_events( + user_id=requester.user.to_string(), + room_id=room_id, + is_admin=True, # already verified above + ) + ret = {"state": room_state} + + return 200, ret + + class JoinRoomAliasServlet(RestServlet): PATTERNS = admin_patterns("/join/(?P<room_identifier>[^/]*)") diff --git a/tests/rest/admin/test_room.py b/tests/rest/admin/test_room.py index a0f32c5512..7c47aa7e0a 100644 --- a/tests/rest/admin/test_room.py +++ b/tests/rest/admin/test_room.py @@ -1180,6 +1180,21 @@ class RoomTestCase(unittest.HomeserverTestCase): ) self.assertEqual(channel.json_body["total"], 3) + def test_room_state(self): + """Test that room state can be requested correctly""" + # Create two test rooms + room_id = self.helper.create_room_as(self.admin_user, tok=self.admin_user_tok) + + url = "/_synapse/admin/v1/rooms/%s/state" % (room_id,) + channel = self.make_request( + "GET", url.encode("ascii"), access_token=self.admin_user_tok, + ) + self.assertEqual(200, channel.code, msg=channel.json_body) + self.assertIn("state", channel.json_body) + # testing that the state events match is painful and not done here. We assume that + # the create_room already does the right thing, so no need to verify that we got + # the state events it created. + class JoinAliasRoomTestCase(unittest.HomeserverTestCase): |