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,
JsonDict,
Requester,
StateMap,
UserID,
UserInfo,
create_requester,
@ -89,6 +90,8 @@ __all__ = [
"PRESENCE_ALL_USERS",
"LoginResponse",
"JsonDict",
"EventBase",
"StateMap",
]
logger = logging.getLogger(__name__)
@ -964,6 +967,52 @@ class ModuleApi:
else:
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:
"""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 synapse.api.constants import EduTypes
from synapse.api.constants import EduTypes, EventTypes
from synapse.events import EventBase
from synapse.federation.units import Transaction
from synapse.handlers.presence import UserPresenceState
@ -509,6 +509,29 @@ class ModuleApiTestCase(HomeserverTestCase):
self.assertEqual(res["displayname"], "simone")
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):
"""For testing ModuleApi functionality in a multi-worker setup"""