Abstract code for stripping room state into a separate method (#8671)
This is a requirement for [knocking](https://github.com/matrix-org/synapse/pull/6739), and is abstracting some code that was originally used by the invite flow. I'm separating it out into this PR as it's a fairly contained change. For a bit of context: when you invite a user to a room, you send them [stripped state events](https://matrix.org/docs/spec/server_server/unstable#put-matrix-federation-v2-invite-roomid-eventid) as part of `invite_room_state`. This is so that their client can display useful information such as the room name and avatar. The same requirement applies to knocking, as it would be nice for clients to be able to display a list of rooms you've knocked on - room name and avatar included. The reason we're sending membership events down as well is in the case that you are invited to a room that does not have an avatar or name set. In that case, the client should use the displayname/avatar of the inviter. That information is located in the inviter's membership event. This is optional as knocks don't really have any user in the room to link up to. When you knock on a room, your knock is sent by you and inserted into the room. It wouldn't *really* make sense to show the avatar of a random user - plus it'd be a data leak. So I've opted not to send membership events to the client here. The UX on the client for when you knock on a room without a name/avatar is a separate problem. In essence this is just moving some inline code to a reusable store method.
This commit is contained in:
parent
4215a3acd4
commit
a699c044b6
|
@ -0,0 +1 @@
|
||||||
|
Abstract some invite-related code in preparation for landing knocking.
|
|
@ -1100,34 +1100,13 @@ class EventCreationHandler:
|
||||||
|
|
||||||
if event.type == EventTypes.Member:
|
if event.type == EventTypes.Member:
|
||||||
if event.content["membership"] == Membership.INVITE:
|
if event.content["membership"] == Membership.INVITE:
|
||||||
|
event.unsigned[
|
||||||
def is_inviter_member_event(e):
|
"invite_room_state"
|
||||||
return e.type == EventTypes.Member and e.sender == event.sender
|
] = await self.store.get_stripped_room_state_from_event_context(
|
||||||
|
context,
|
||||||
current_state_ids = await context.get_current_state_ids()
|
self.room_invite_state_types,
|
||||||
|
membership_user_id=event.sender,
|
||||||
# We know this event is not an outlier, so this must be
|
)
|
||||||
# non-None.
|
|
||||||
assert current_state_ids is not None
|
|
||||||
|
|
||||||
state_to_include_ids = [
|
|
||||||
e_id
|
|
||||||
for k, e_id in current_state_ids.items()
|
|
||||||
if k[0] in self.room_invite_state_types
|
|
||||||
or k == (EventTypes.Member, event.sender)
|
|
||||||
]
|
|
||||||
|
|
||||||
state_to_include = await self.store.get_events(state_to_include_ids)
|
|
||||||
|
|
||||||
event.unsigned["invite_room_state"] = [
|
|
||||||
{
|
|
||||||
"type": e.type,
|
|
||||||
"state_key": e.state_key,
|
|
||||||
"content": e.content,
|
|
||||||
"sender": e.sender,
|
|
||||||
}
|
|
||||||
for e in state_to_include.values()
|
|
||||||
]
|
|
||||||
|
|
||||||
invitee = UserID.from_string(event.state_key)
|
invitee = UserID.from_string(event.state_key)
|
||||||
if not self.hs.is_mine(invitee):
|
if not self.hs.is_mine(invitee):
|
||||||
|
|
|
@ -31,6 +31,7 @@ from synapse.api.room_versions import (
|
||||||
RoomVersions,
|
RoomVersions,
|
||||||
)
|
)
|
||||||
from synapse.events import EventBase, make_event_from_dict
|
from synapse.events import EventBase, make_event_from_dict
|
||||||
|
from synapse.events.snapshot import EventContext
|
||||||
from synapse.events.utils import prune_event
|
from synapse.events.utils import prune_event
|
||||||
from synapse.logging.context import PreserveLoggingContext, current_context
|
from synapse.logging.context import PreserveLoggingContext, current_context
|
||||||
from synapse.metrics.background_process_metrics import (
|
from synapse.metrics.background_process_metrics import (
|
||||||
|
@ -44,7 +45,7 @@ from synapse.storage._base import SQLBaseStore, db_to_json, make_in_list_sql_cla
|
||||||
from synapse.storage.database import DatabasePool
|
from synapse.storage.database import DatabasePool
|
||||||
from synapse.storage.engines import PostgresEngine
|
from synapse.storage.engines import PostgresEngine
|
||||||
from synapse.storage.util.id_generators import MultiWriterIdGenerator, StreamIdGenerator
|
from synapse.storage.util.id_generators import MultiWriterIdGenerator, StreamIdGenerator
|
||||||
from synapse.types import Collection, get_domain_from_id
|
from synapse.types import Collection, JsonDict, get_domain_from_id
|
||||||
from synapse.util.caches.descriptors import cached
|
from synapse.util.caches.descriptors import cached
|
||||||
from synapse.util.caches.lrucache import LruCache
|
from synapse.util.caches.lrucache import LruCache
|
||||||
from synapse.util.iterutils import batch_iter
|
from synapse.util.iterutils import batch_iter
|
||||||
|
@ -525,6 +526,57 @@ class EventsWorkerStore(SQLBaseStore):
|
||||||
|
|
||||||
return event_map
|
return event_map
|
||||||
|
|
||||||
|
async def get_stripped_room_state_from_event_context(
|
||||||
|
self,
|
||||||
|
context: EventContext,
|
||||||
|
state_types_to_include: List[EventTypes],
|
||||||
|
membership_user_id: Optional[str],
|
||||||
|
) -> List[JsonDict]:
|
||||||
|
"""
|
||||||
|
Retrieve the stripped state from a room, given an event context to retrieve state
|
||||||
|
from as well as the state types to include. Optionally, include the membership
|
||||||
|
events from a specific user.
|
||||||
|
|
||||||
|
"Stripped" state means that only the `type`, `state_key`, `content` and `sender` keys
|
||||||
|
are included from each state event.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
context: The event context to retrieve state of the room from.
|
||||||
|
state_types_to_include: The type of state events to include.
|
||||||
|
membership_user_id: An optional user ID to include the stripped membership state
|
||||||
|
events of. This is useful when generating the stripped state of a room for
|
||||||
|
invites. We want to send membership events of the inviter, so that the
|
||||||
|
invitee can display the inviter's profile information if the room lacks any.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of dictionaries, each representing a stripped state event from the room.
|
||||||
|
"""
|
||||||
|
current_state_ids = await context.get_current_state_ids()
|
||||||
|
|
||||||
|
# We know this event is not an outlier, so this must be
|
||||||
|
# non-None.
|
||||||
|
assert current_state_ids is not None
|
||||||
|
|
||||||
|
# The state to include
|
||||||
|
state_to_include_ids = [
|
||||||
|
e_id
|
||||||
|
for k, e_id in current_state_ids.items()
|
||||||
|
if k[0] in state_types_to_include
|
||||||
|
or (membership_user_id and k == (EventTypes.Member, membership_user_id))
|
||||||
|
]
|
||||||
|
|
||||||
|
state_to_include = await self.get_events(state_to_include_ids)
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"type": e.type,
|
||||||
|
"state_key": e.state_key,
|
||||||
|
"content": e.content,
|
||||||
|
"sender": e.sender,
|
||||||
|
}
|
||||||
|
for e in state_to_include.values()
|
||||||
|
]
|
||||||
|
|
||||||
def _do_fetch(self, conn):
|
def _do_fetch(self, conn):
|
||||||
"""Takes a database connection and waits for requests for events from
|
"""Takes a database connection and waits for requests for events from
|
||||||
the _event_fetch_list queue.
|
the _event_fetch_list queue.
|
||||||
|
|
Loading…
Reference in New Issue