This commit is contained in:
Shay 2025-03-13 15:12:19 +03:00 committed by GitHub
commit 859dfa9a87
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 118 additions and 1 deletions

View file

@ -0,0 +1 @@
Add a query param `participant` to `/members` admin api to filter for room participants.

View file

@ -358,6 +358,13 @@ The API is:
GET /_synapse/admin/v1/rooms/<room_id>/members
```
**Parameters**
The following query parameters are available:
* `participant` - Optional. If provided and set to true, only returns currently joined members who have
also posted to the room. Defaults to false.
A response body like the following is returned:
```json

View file

@ -435,7 +435,12 @@ class RoomMembersRestServlet(RestServlet):
if not room:
raise NotFoundError("Room not found")
members = await self.store.get_users_in_room(room_id)
participant = parse_boolean(request, "participant", False)
if participant:
members = await self.store.get_participants_in_room(room_id)
else:
members = await self.store.get_users_in_room(room_id)
ret = {"members": members, "total": len(members)}
return HTTPStatus.OK, ret

View file

@ -1606,6 +1606,34 @@ class RoomMemberWorkerStore(EventsWorkerStore, CacheInvalidationWorkerStore):
from_ts,
)
async def get_participants_in_room(self, room_id: str) -> Sequence[str]:
"""
Return a list of all currently joined room members who have posted
in the given room.
Args:
room_id: room ID of the room to search in
"""
def _get_participants_in_room_txn(
txn: LoggingTransaction, room_id: str
) -> List[str]:
sql = """
SELECT DISTINCT c.state_key
FROM current_state_events AS c
INNER JOIN events AS e USING(room_id)
WHERE room_id = ?
AND c.membership = 'join'
AND e.type = 'm.room.message'
AND c.state_key = e.sender
"""
txn.execute(sql, (room_id,))
return [r[0] for r in txn]
return await self.db_pool.runInteraction(
"_get_participants_in_room_txn", _get_participants_in_room_txn, room_id
)
class RoomMemberBackgroundUpdateStore(SQLBaseStore):
def __init__(

View file

@ -2021,6 +2021,82 @@ class RoomTestCase(unittest.HomeserverTestCase):
)
self.assertEqual(channel.json_body["total"], 3)
def test_room_members_participants_param(self) -> None:
"""
Test that /_synapse/admin/v1/rooms/{room_id}/members with a query param value of
participant=true returns a list of currently joined users who have posted, and
that the list does not contain room members who have not posted
"""
participant = self.register_user("participant", "pass")
participant_tok = self.login("participant", "pass")
room_id = self.helper.create_room_as(participant, tok=participant_tok)
participant2 = self.register_user("participant2", "pass")
participant2_tok = self.login("participant2", "pass")
self.helper.join(room_id, participant2, tok=participant2_tok)
# have some lurkers join the room
for i in range(5):
user = self.register_user(f"user{i}", "pass")
user_tok = self.login(f"user{i}", "pass")
self.helper.join(room_id, user, tok=user_tok)
# double-check the room membership total, should be 7
channel = self.make_request(
"GET",
f"/_synapse/admin/v1/rooms/{room_id}/members",
access_token=self.admin_user_tok,
)
self.assertEqual(200, channel.code)
self.assertEqual(channel.json_body["total"], 7)
# participants send messages
self.helper.send_event(
room_id,
"m.room.message",
content={
"msgtype": "m.text",
"body": "nefarious activity",
},
tok=participant_tok,
)
self.helper.send_event(
room_id,
"m.room.message",
content={
"msgtype": "m.text",
"body": "more nefarious activity",
},
tok=participant2_tok,
)
channel = self.make_request(
"GET",
f"/_synapse/admin/v1/rooms/{room_id}/members?participant=true",
access_token=self.admin_user_tok,
)
self.assertEqual(200, channel.code)
participants = channel.json_body["members"]
self.assertEqual(channel.json_body["total"], 2)
self.assertIn(participant, participants)
self.assertIn(participant2, participants)
# have participants leave room
self.helper.leave(room_id, participant, tok=participant_tok)
self.helper.leave(room_id, participant2, tok=participant2_tok)
# there should no longer be any active participants
channel = self.make_request(
"GET",
f"/_synapse/admin/v1/rooms/{room_id}/members?participant=true",
access_token=self.admin_user_tok,
)
self.assertEqual(200, channel.code)
participants = channel.json_body["total"]
self.assertEqual(participants, 0)
def test_room_state(self) -> None:
"""Test that room state can be requested correctly"""
# Create two test rooms