|
|
|
@ -25,7 +25,13 @@ from twisted.internet import defer |
|
|
|
|
from twisted.internet.defer import succeed |
|
|
|
|
|
|
|
|
|
from synapse.api.constants import MAX_DEPTH, EventTypes, Membership |
|
|
|
|
from synapse.api.errors import AuthError, Codes, ConsentNotGivenError, SynapseError |
|
|
|
|
from synapse.api.errors import ( |
|
|
|
|
AuthError, |
|
|
|
|
Codes, |
|
|
|
|
ConsentNotGivenError, |
|
|
|
|
NotFoundError, |
|
|
|
|
SynapseError, |
|
|
|
|
) |
|
|
|
|
from synapse.api.urls import ConsentURIBuilder |
|
|
|
|
from synapse.crypto.event_signing import add_hashes_and_signatures |
|
|
|
|
from synapse.events.utils import serialize_event |
|
|
|
@ -36,6 +42,7 @@ from synapse.util.async_helpers import Linearizer |
|
|
|
|
from synapse.util.frozenutils import frozendict_json_encoder |
|
|
|
|
from synapse.util.logcontext import run_in_background |
|
|
|
|
from synapse.util.metrics import measure_func |
|
|
|
|
from synapse.visibility import filter_events_for_client |
|
|
|
|
|
|
|
|
|
from ._base import BaseHandler |
|
|
|
|
|
|
|
|
@ -82,26 +89,83 @@ class MessageHandler(object): |
|
|
|
|
defer.returnValue(data) |
|
|
|
|
|
|
|
|
|
@defer.inlineCallbacks |
|
|
|
|
def get_state_events(self, user_id, room_id, is_guest=False): |
|
|
|
|
def get_state_events( |
|
|
|
|
self, user_id, room_id, types=None, filtered_types=None, |
|
|
|
|
at_token=None, is_guest=False, |
|
|
|
|
): |
|
|
|
|
"""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 |
|
|
|
|
left the room return the state events from when they left. |
|
|
|
|
left the room return the state events from when they left. If an explicit |
|
|
|
|
'at' parameter is passed, return the state events as of that event, if |
|
|
|
|
visible. |
|
|
|
|
|
|
|
|
|
Args: |
|
|
|
|
user_id(str): The user requesting state events. |
|
|
|
|
room_id(str): The room ID to get all state events from. |
|
|
|
|
types(list[(str, str|None)]|None): List of (type, state_key) tuples |
|
|
|
|
which are used to filter the state fetched. If `state_key` is None, |
|
|
|
|
all events are returned of the given type. |
|
|
|
|
May be None, which matches any key. |
|
|
|
|
filtered_types(list[str]|None): Only apply filtering via `types` to this |
|
|
|
|
list of event types. Other types of events are returned unfiltered. |
|
|
|
|
If None, `types` filtering is applied to all events. |
|
|
|
|
at_token(StreamToken|None): the stream token of the at which we are requesting |
|
|
|
|
the stats. If the user is not allowed to view the state as of that |
|
|
|
|
stream token, we raise a 403 SynapseError. If None, returns the current |
|
|
|
|
state based on the current_state_events table. |
|
|
|
|
is_guest(bool): whether this user is a guest |
|
|
|
|
Returns: |
|
|
|
|
A list of dicts representing state events. [{}, {}, {}] |
|
|
|
|
Raises: |
|
|
|
|
NotFoundError (404) if the at token does not yield an event |
|
|
|
|
|
|
|
|
|
AuthError (403) if the user doesn't have permission to view |
|
|
|
|
members of this room. |
|
|
|
|
""" |
|
|
|
|
membership, membership_event_id = yield self.auth.check_in_room_or_world_readable( |
|
|
|
|
room_id, user_id |
|
|
|
|
if at_token: |
|
|
|
|
# FIXME this claims to get the state at a stream position, but |
|
|
|
|
# get_recent_events_for_room operates by topo ordering. This therefore |
|
|
|
|
# does not reliably give you the state at the given stream position. |
|
|
|
|
# (https://github.com/matrix-org/synapse/issues/3305) |
|
|
|
|
last_events, _ = yield self.store.get_recent_events_for_room( |
|
|
|
|
room_id, end_token=at_token.room_key, limit=1, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
if not last_events: |
|
|
|
|
raise NotFoundError("Can't find event for token %s" % (at_token, )) |
|
|
|
|
|
|
|
|
|
visible_events = yield filter_events_for_client( |
|
|
|
|
self.store, user_id, last_events, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
event = last_events[0] |
|
|
|
|
if visible_events: |
|
|
|
|
room_state = yield self.store.get_state_for_events( |
|
|
|
|
[event.event_id], types, filtered_types=filtered_types, |
|
|
|
|
) |
|
|
|
|
room_state = room_state[event.event_id] |
|
|
|
|
else: |
|
|
|
|
raise AuthError( |
|
|
|
|
403, |
|
|
|
|
"User %s not allowed to view events in room %s at token %s" % ( |
|
|
|
|
user_id, room_id, at_token, |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
else: |
|
|
|
|
membership, membership_event_id = ( |
|
|
|
|
yield self.auth.check_in_room_or_world_readable( |
|
|
|
|
room_id, user_id, |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
if membership == Membership.JOIN: |
|
|
|
|
room_state = yield self.state.get_current_state(room_id) |
|
|
|
|
state_ids = yield self.store.get_filtered_current_state_ids( |
|
|
|
|
room_id, types, filtered_types=filtered_types, |
|
|
|
|
) |
|
|
|
|
room_state = yield self.store.get_events(state_ids.values()) |
|
|
|
|
elif membership == Membership.LEAVE: |
|
|
|
|
room_state = yield self.store.get_state_for_events( |
|
|
|
|
[membership_event_id], None |
|
|
|
|
[membership_event_id], types, filtered_types=filtered_types, |
|
|
|
|
) |
|
|
|
|
room_state = room_state[membership_event_id] |
|
|
|
|
|
|
|
|
|