Add a module API method to retrieve state from a room (#11204)

This commit is contained in:
Brendan Abolivier 2021-10-29 18:28:29 +02:00 committed by GitHub
parent 3ed17ff651
commit ad4eab9862
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 1 deletions

View File

@ -0,0 +1 @@
Add a module API method to retrieve the current state of a room.

View File

@ -55,6 +55,7 @@ from synapse.types import (
DomainSpecificString, DomainSpecificString,
JsonDict, JsonDict,
Requester, Requester,
StateMap,
UserID, UserID,
UserInfo, UserInfo,
create_requester, create_requester,
@ -89,6 +90,8 @@ __all__ = [
"PRESENCE_ALL_USERS", "PRESENCE_ALL_USERS",
"LoginResponse", "LoginResponse",
"JsonDict", "JsonDict",
"EventBase",
"StateMap",
] ]
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -964,6 +967,52 @@ class ModuleApi:
else: else:
return [] return []
async def get_room_state(
self,
room_id: str,
event_filter: Optional[Iterable[Tuple[str, Optional[str]]]] = None,
) -> StateMap[EventBase]:
"""Returns the current state of the given room.
The events are returned as a mapping, in which the key for each event is a tuple
which first element is the event's type and the second one is its state key.
Added in Synapse v1.47.0
Args:
room_id: The ID of the room to get state from.
event_filter: A filter to apply when retrieving events. None if no filter
should be applied. If provided, must be an iterable of tuples. A tuple's
first element is the event type and the second is the state key, or is
None if the state key should not be filtered on.
An example of a filter is:
[
("m.room.member", "@alice:example.com"), # Member event for @alice:example.com
("org.matrix.some_event", ""), # State event of type "org.matrix.some_event"
# with an empty string as its state key
("org.matrix.some_other_event", None), # State events of type "org.matrix.some_other_event"
# regardless of their state key
]
"""
if event_filter:
# If a filter was provided, turn it into a StateFilter and retrieve a filtered
# view of the state.
state_filter = StateFilter.from_types(event_filter)
state_ids = await self._store.get_filtered_current_state_ids(
room_id,
state_filter,
)
else:
# If no filter was provided, get the whole state. We could also reuse the call
# to get_filtered_current_state_ids above, with `state_filter = StateFilter.all()`,
# but get_filtered_current_state_ids isn't cached and `get_current_state_ids`
# is, so using the latter when we can is better for perf.
state_ids = await self._store.get_current_state_ids(room_id)
state_events = await self._store.get_events(state_ids.values())
return {key: state_events[event_id] for key, event_id in state_ids.items()}
class PublicRoomListManager: class PublicRoomListManager:
"""Contains methods for adding to, removing from and querying whether a room """Contains methods for adding to, removing from and querying whether a room

View File

@ -15,7 +15,7 @@ from unittest.mock import Mock
from twisted.internet import defer from twisted.internet import defer
from synapse.api.constants import EduTypes from synapse.api.constants import EduTypes, EventTypes
from synapse.events import EventBase from synapse.events import EventBase
from synapse.federation.units import Transaction from synapse.federation.units import Transaction
from synapse.handlers.presence import UserPresenceState from synapse.handlers.presence import UserPresenceState
@ -509,6 +509,29 @@ class ModuleApiTestCase(HomeserverTestCase):
self.assertEqual(res["displayname"], "simone") self.assertEqual(res["displayname"], "simone")
self.assertIsNone(res["avatar_url"]) self.assertIsNone(res["avatar_url"])
def test_get_room_state(self):
"""Tests that a module can retrieve the state of a room through the module API."""
user_id = self.register_user("peter", "hackme")
tok = self.login("peter", "hackme")
# Create a room and send some custom state in it.
room_id = self.helper.create_room_as(tok=tok)
self.helper.send_state(room_id, "org.matrix.test", {}, tok=tok)
# Check that the module API can successfully fetch state for the room.
state = self.get_success(
defer.ensureDeferred(self.module_api.get_room_state(room_id))
)
# Check that a few standard events are in the returned state.
self.assertIn((EventTypes.Create, ""), state)
self.assertIn((EventTypes.Member, user_id), state)
# Check that our custom state event is in the returned state.
self.assertEqual(state[("org.matrix.test", "")].sender, user_id)
self.assertEqual(state[("org.matrix.test", "")].state_key, "")
self.assertEqual(state[("org.matrix.test", "")].content, {})
class ModuleApiWorkerTestCase(BaseMultiWorkerStreamTestCase): class ModuleApiWorkerTestCase(BaseMultiWorkerStreamTestCase):
"""For testing ModuleApi functionality in a multi-worker setup""" """For testing ModuleApi functionality in a multi-worker setup"""