From 8d582513f3afaa58efdf818d62043c0587c2b464 Mon Sep 17 00:00:00 2001 From: Michael Albert Date: Tue, 7 Jul 2020 14:43:10 +0200 Subject: [PATCH 1/7] Add room members admin endpoint Signed-off-by: Michael Albert --- docs/admin_api/rooms.md | 27 +++++++++++++++++++++ synapse/rest/admin/__init__.py | 2 ++ synapse/rest/admin/rooms.py | 22 +++++++++++++++++ tests/rest/admin/test_room.py | 43 ++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+) diff --git a/docs/admin_api/rooms.md b/docs/admin_api/rooms.md index 624e7745baa7..cef1fa12ac4c 100644 --- a/docs/admin_api/rooms.md +++ b/docs/admin_api/rooms.md @@ -318,3 +318,30 @@ Response: "state_events": 93534 } ``` + +# Room Members API + +The Room Members admin API allows server admins to get a list of all members of a room. + +## Usage + +A standard request: + +``` +GET /_synapse/admin/v1/rooms//members + +{} +``` + +Response: + +``` +{ + "members": [ + "@foo:matrix.org", + "@bar:matrix.org", + "@foobar:matrix.org + ], + "total": 3 +} +``` diff --git a/synapse/rest/admin/__init__.py b/synapse/rest/admin/__init__.py index 9eda592de9f7..e5aabb2c2f8f 100644 --- a/synapse/rest/admin/__init__.py +++ b/synapse/rest/admin/__init__.py @@ -38,6 +38,7 @@ JoinRoomAliasServlet, ListRoomRestServlet, RoomRestServlet, + RoomMembersRestServlet, ShutdownRoomRestServlet, ) from synapse.rest.admin.server_notice_servlet import SendServerNoticeServlet @@ -200,6 +201,7 @@ def register_servlets(hs, http_server): register_servlets_for_client_rest_resource(hs, http_server) ListRoomRestServlet(hs).register(http_server) RoomRestServlet(hs).register(http_server) + RoomMembersRestServlet(hs).register(http_server) JoinRoomAliasServlet(hs).register(http_server) PurgeRoomServlet(hs).register(http_server) SendServerNoticeServlet(hs).register(http_server) diff --git a/synapse/rest/admin/rooms.py b/synapse/rest/admin/rooms.py index e07c32118db8..4b0dc74cf692 100644 --- a/synapse/rest/admin/rooms.py +++ b/synapse/rest/admin/rooms.py @@ -291,6 +291,28 @@ async def on_GET(self, request, room_id): return 200, ret +class RoomMembersRestServlet(RestServlet): + """ + Get members list of a room. + """ + + PATTERNS = admin_patterns("/rooms/(?P[^/]+)/members") + + def __init__(self, hs): + self.hs = hs + self.auth = hs.get_auth() + self.store = hs.get_datastore() + + async def on_GET(self, request, room_id): + await assert_requester_is_admin(self.auth, request) + + members = await self.store.get_users_in_room(room_id) + if not members: + raise NotFoundError("Room not found") + + ret = {'members': members, 'total': len(members)} + + return 200, ret class JoinRoomAliasServlet(RestServlet): diff --git a/tests/rest/admin/test_room.py b/tests/rest/admin/test_room.py index 54cd24bf645d..534c7c934ad6 100644 --- a/tests/rest/admin/test_room.py +++ b/tests/rest/admin/test_room.py @@ -742,6 +742,49 @@ def test_single_room(self): self.assertEqual(room_id_1, channel.json_body["room_id"]) + def test_room_members(self): + """Test that room members can be requested correctly""" + # Create two test rooms + room_id_1 = self.helper.create_room_as(self.admin_user, tok=self.admin_user_tok) + room_id_2 = self.helper.create_room_as(self.admin_user, tok=self.admin_user_tok) + + # Have another user join the room + user_1 = self.register_user("foo", "pass") + user_tok_1 = self.login("foo", "pass") + self.helper.join(room_id_1, user_1, tok=user_tok_1) + + # Have another user join the room + user_2 = self.register_user("bar", "pass") + user_tok_2 = self.login("bar", "pass") + self.helper.join(room_id_1, user_2, tok=user_tok_2) + self.helper.join(room_id_2, user_2, tok=user_tok_2) + + # Have another user join the room + user_3 = self.register_user("foobar", "pass") + user_tok_3 = self.login("foobar", "pass") + self.helper.join(room_id_2, user_3, tok=user_tok_3) + + url = "/_synapse/admin/v1/rooms/%s/members" % (room_id_1,) + request, channel = self.make_request( + "GET", url.encode("ascii"), access_token=self.admin_user_tok, + ) + self.render(request) + self.assertEqual(200, channel.code, msg=channel.json_body) + + self.assertIn("@foo:test", channel.json_body["members"]) + self.assertIn("@bar:test", channel.json_body["members"]) + self.assertEqual(channel.json_body["total"], 3) + + url = "/_synapse/admin/v1/rooms/%s/members" % (room_id_2,) + request, channel = self.make_request( + "GET", url.encode("ascii"), access_token=self.admin_user_tok, + ) + self.render(request) + self.assertEqual(200, channel.code, msg=channel.json_body) + + self.assertIn("@bar:test", channel.json_body["members"]) + self.assertIn("@foobar:test", channel.json_body["members"]) + self.assertEqual(channel.json_body["total"], 3) class JoinAliasRoomTestCase(unittest.HomeserverTestCase): From 513fe7ed688a3c86e881699415b9522ada131b41 Mon Sep 17 00:00:00 2001 From: Michael Albert Date: Tue, 14 Jul 2020 12:20:21 +0200 Subject: [PATCH 2/7] Add changelog file --- changelog.d/7842.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7842.feature diff --git a/changelog.d/7842.feature b/changelog.d/7842.feature new file mode 100644 index 000000000000..592d52f8fcd9 --- /dev/null +++ b/changelog.d/7842.feature @@ -0,0 +1 @@ +Add room members admin endpoint. Contributed by Awesome Technologies Innovationslabor GmbH. From 71f0de77404dcad05c6d19c309436a4269e1c327 Mon Sep 17 00:00:00 2001 From: Michael Albert Date: Tue, 14 Jul 2020 12:26:25 +0200 Subject: [PATCH 3/7] Fix style --- synapse/rest/admin/__init__.py | 2 +- synapse/rest/admin/rooms.py | 4 +++- tests/rest/admin/test_room.py | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/synapse/rest/admin/__init__.py b/synapse/rest/admin/__init__.py index e5aabb2c2f8f..18baaadb1ec2 100644 --- a/synapse/rest/admin/__init__.py +++ b/synapse/rest/admin/__init__.py @@ -37,8 +37,8 @@ from synapse.rest.admin.rooms import ( JoinRoomAliasServlet, ListRoomRestServlet, - RoomRestServlet, RoomMembersRestServlet, + RoomRestServlet, ShutdownRoomRestServlet, ) from synapse.rest.admin.server_notice_servlet import SendServerNoticeServlet diff --git a/synapse/rest/admin/rooms.py b/synapse/rest/admin/rooms.py index 4b0dc74cf692..8134a8d75ac0 100644 --- a/synapse/rest/admin/rooms.py +++ b/synapse/rest/admin/rooms.py @@ -291,6 +291,7 @@ async def on_GET(self, request, room_id): return 200, ret + class RoomMembersRestServlet(RestServlet): """ Get members list of a room. @@ -310,10 +311,11 @@ async def on_GET(self, request, room_id): if not members: raise NotFoundError("Room not found") - ret = {'members': members, 'total': len(members)} + ret = {"members": members, "total": len(members)} return 200, ret + class JoinRoomAliasServlet(RestServlet): PATTERNS = admin_patterns("/join/(?P[^/]*)") diff --git a/tests/rest/admin/test_room.py b/tests/rest/admin/test_room.py index 534c7c934ad6..c14e407c7684 100644 --- a/tests/rest/admin/test_room.py +++ b/tests/rest/admin/test_room.py @@ -786,6 +786,7 @@ def test_room_members(self): self.assertIn("@foobar:test", channel.json_body["members"]) self.assertEqual(channel.json_body["total"], 3) + class JoinAliasRoomTestCase(unittest.HomeserverTestCase): servlets = [ From 50384b60a6bae915f7b88d771076b32a66d107ed Mon Sep 17 00:00:00 2001 From: Michael Albert Date: Tue, 14 Jul 2020 20:55:26 +0200 Subject: [PATCH 4/7] Add requested changes --- changelog.d/7842.feature | 2 +- docs/admin_api/rooms.md | 7 ++++++- synapse/rest/admin/rooms.py | 3 ++- tests/rest/admin/test_room.py | 6 ++---- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/changelog.d/7842.feature b/changelog.d/7842.feature index 592d52f8fcd9..727deb01c9a7 100644 --- a/changelog.d/7842.feature +++ b/changelog.d/7842.feature @@ -1 +1 @@ -Add room members admin endpoint. Contributed by Awesome Technologies Innovationslabor GmbH. +Add an admin API to list the users in a room. Contributed by Awesome Technologies Innovationslabor GmbH. diff --git a/docs/admin_api/rooms.md b/docs/admin_api/rooms.md index 58e78f1e2708..15b83e98248b 100644 --- a/docs/admin_api/rooms.md +++ b/docs/admin_api/rooms.md @@ -323,6 +323,11 @@ Response: The Room Members admin API allows server admins to get a list of all members of a room. +The response includes the following fields: + +* `members` - A list of all the members that are present in the room, represented by their ids. +* `total` - Total number of members in the room. + ## Usage A standard request: @@ -350,7 +355,7 @@ Response: The Delete Room admin API allows server admins to remove rooms from server and block these rooms. -It is a combination and improvement of "[Shutdown room](shutdown_room.md)" +It is a combination and improvement of "[Shutdown room](shutdown_room.md)" and "[Purge room](purge_room.md)" API. Shuts down a room. Moves all local users and room aliases automatically to a diff --git a/synapse/rest/admin/rooms.py b/synapse/rest/admin/rooms.py index 28c42ff8c713..611923d547f2 100644 --- a/synapse/rest/admin/rooms.py +++ b/synapse/rest/admin/rooms.py @@ -248,7 +248,8 @@ async def on_GET(self, request, room_id): members = await self.store.get_users_in_room(room_id) if not members: - raise NotFoundError("Room not found") + print(members) + raise NotFoundError("Room not found or empty") ret = {"members": members, "total": len(members)} diff --git a/tests/rest/admin/test_room.py b/tests/rest/admin/test_room.py index bc4b514eb58f..5973d3e7a08b 100644 --- a/tests/rest/admin/test_room.py +++ b/tests/rest/admin/test_room.py @@ -1165,8 +1165,7 @@ def test_room_members(self): self.render(request) self.assertEqual(200, channel.code, msg=channel.json_body) - self.assertIn("@foo:test", channel.json_body["members"]) - self.assertIn("@bar:test", channel.json_body["members"]) + self.assertCountEqual(["@admin:test", "@foo:test", "@bar:test"], channel.json_body["members"]) self.assertEqual(channel.json_body["total"], 3) url = "/_synapse/admin/v1/rooms/%s/members" % (room_id_2,) @@ -1176,8 +1175,7 @@ def test_room_members(self): self.render(request) self.assertEqual(200, channel.code, msg=channel.json_body) - self.assertIn("@bar:test", channel.json_body["members"]) - self.assertIn("@foobar:test", channel.json_body["members"]) + self.assertCountEqual(["@admin:test", "@bar:test", "@foobar:test"], channel.json_body["members"]) self.assertEqual(channel.json_body["total"], 3) From fb1b0a1a00023e9c9b50debe984405b30e35ba5a Mon Sep 17 00:00:00 2001 From: Michael Albert Date: Tue, 14 Jul 2020 22:01:32 +0200 Subject: [PATCH 5/7] Remove print --- synapse/rest/admin/rooms.py | 1 - 1 file changed, 1 deletion(-) diff --git a/synapse/rest/admin/rooms.py b/synapse/rest/admin/rooms.py index 611923d547f2..cbeec7736680 100644 --- a/synapse/rest/admin/rooms.py +++ b/synapse/rest/admin/rooms.py @@ -248,7 +248,6 @@ async def on_GET(self, request, room_id): members = await self.store.get_users_in_room(room_id) if not members: - print(members) raise NotFoundError("Room not found or empty") ret = {"members": members, "total": len(members)} From d032f954d0e1d066adf80d136ed5c224c7cc4081 Mon Sep 17 00:00:00 2001 From: Michael Albert Date: Tue, 14 Jul 2020 22:05:58 +0200 Subject: [PATCH 6/7] Fix style --- tests/rest/admin/test_room.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/rest/admin/test_room.py b/tests/rest/admin/test_room.py index 5973d3e7a08b..946f06d151f7 100644 --- a/tests/rest/admin/test_room.py +++ b/tests/rest/admin/test_room.py @@ -1165,7 +1165,9 @@ def test_room_members(self): self.render(request) self.assertEqual(200, channel.code, msg=channel.json_body) - self.assertCountEqual(["@admin:test", "@foo:test", "@bar:test"], channel.json_body["members"]) + self.assertCountEqual( + ["@admin:test", "@foo:test", "@bar:test"], channel.json_body["members"] + ) self.assertEqual(channel.json_body["total"], 3) url = "/_synapse/admin/v1/rooms/%s/members" % (room_id_2,) @@ -1175,7 +1177,9 @@ def test_room_members(self): self.render(request) self.assertEqual(200, channel.code, msg=channel.json_body) - self.assertCountEqual(["@admin:test", "@bar:test", "@foobar:test"], channel.json_body["members"]) + self.assertCountEqual( + ["@admin:test", "@bar:test", "@foobar:test"], channel.json_body["members"] + ) self.assertEqual(channel.json_body["total"], 3) From 5da5f9c263ac83bda40a887bd681d3e20128b6bc Mon Sep 17 00:00:00 2001 From: Michael Albert Date: Thu, 16 Jul 2020 22:07:52 +0200 Subject: [PATCH 7/7] Add check for room existance --- synapse/rest/admin/rooms.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/synapse/rest/admin/rooms.py b/synapse/rest/admin/rooms.py index cbeec7736680..b8c95d045a74 100644 --- a/synapse/rest/admin/rooms.py +++ b/synapse/rest/admin/rooms.py @@ -246,10 +246,11 @@ def __init__(self, hs): async def on_GET(self, request, room_id): await assert_requester_is_admin(self.auth, request) - members = await self.store.get_users_in_room(room_id) - if not members: - raise NotFoundError("Room not found or empty") + ret = await self.store.get_room(room_id) + if not ret: + raise NotFoundError("Room not found") + members = await self.store.get_users_in_room(room_id) ret = {"members": members, "total": len(members)} return 200, ret