mirror of
https://github.com/element-hq/synapse
synced 2024-07-04 08:43:29 +00:00
Just stripped_state for invite rooms
This commit is contained in:
parent
3568311989
commit
7aea406c22
|
@ -755,14 +755,23 @@ class SlidingSyncHandler:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Assemble the list of timeline events
|
# Assemble the list of timeline events
|
||||||
timeline_events: List[EventBase] = []
|
timeline_events: Optional[List[EventBase]] = None
|
||||||
limited = False
|
limited: Optional[bool] = None
|
||||||
# We want to start off using the `to_token` (vs `from_token`) because we look
|
prev_batch_token: Optional[StreamToken] = None
|
||||||
# backwards from the `to_token` up to the `timeline_limit` and we might not
|
num_live: Optional[int] = None
|
||||||
# reach the `from_token` before we hit the limit. We will update the room stream
|
if (
|
||||||
# position once we've fetched the events to point to the earliest event fetched.
|
room_sync_config.timeline_limit > 0
|
||||||
prev_batch_token = to_token
|
# No timeline for invite/knock rooms (just `stripped_state`)
|
||||||
if room_sync_config.timeline_limit > 0:
|
and rooms_for_user_membership_at_to_token.membership
|
||||||
|
not in (Membership.INVITE, Membership.KNOCK)
|
||||||
|
):
|
||||||
|
limited = False
|
||||||
|
# We want to start off using the `to_token` (vs `from_token`) because we look
|
||||||
|
# backwards from the `to_token` up to the `timeline_limit` and we might not
|
||||||
|
# reach the `from_token` before we hit the limit. We will update the room stream
|
||||||
|
# position once we've fetched the events to point to the earliest event fetched.
|
||||||
|
prev_batch_token = to_token
|
||||||
|
|
||||||
newly_joined = False
|
newly_joined = False
|
||||||
if (
|
if (
|
||||||
# We can only determine new-ness if we have a `from_token` to define our range
|
# We can only determine new-ness if we have a `from_token` to define our range
|
||||||
|
@ -903,7 +912,7 @@ class SlidingSyncHandler:
|
||||||
# If the timeline is `limited=True`, the client does not have all events
|
# If the timeline is `limited=True`, the client does not have all events
|
||||||
# necessary to calculate aggregations themselves.
|
# necessary to calculate aggregations themselves.
|
||||||
bundled_aggregations = None
|
bundled_aggregations = None
|
||||||
if limited:
|
if limited and timeline_events is not None:
|
||||||
bundled_aggregations = (
|
bundled_aggregations = (
|
||||||
await self.relations_handler.get_bundled_aggregations(
|
await self.relations_handler.get_bundled_aggregations(
|
||||||
timeline_events, user.to_string()
|
timeline_events, user.to_string()
|
||||||
|
|
|
@ -973,31 +973,13 @@ class SlidingSyncRestServlet(RestServlet):
|
||||||
requester=requester,
|
requester=requester,
|
||||||
)
|
)
|
||||||
|
|
||||||
serialized_rooms = {}
|
serialized_rooms: Dict[str, JsonDict] = {}
|
||||||
for room_id, room_result in rooms.items():
|
for room_id, room_result in rooms.items():
|
||||||
serialized_timeline = await self.event_serializer.serialize_events(
|
|
||||||
room_result.timeline_events,
|
|
||||||
time_now,
|
|
||||||
config=serialize_options,
|
|
||||||
bundle_aggregations=room_result.bundled_aggregations,
|
|
||||||
)
|
|
||||||
|
|
||||||
serialized_required_state = await self.event_serializer.serialize_events(
|
|
||||||
room_result.required_state,
|
|
||||||
time_now,
|
|
||||||
config=serialize_options,
|
|
||||||
)
|
|
||||||
|
|
||||||
serialized_rooms[room_id] = {
|
serialized_rooms[room_id] = {
|
||||||
"required_state": serialized_required_state,
|
|
||||||
"timeline": serialized_timeline,
|
|
||||||
"prev_batch": await room_result.prev_batch.to_string(self.store),
|
|
||||||
"limited": room_result.limited,
|
|
||||||
"joined_count": room_result.joined_count,
|
"joined_count": room_result.joined_count,
|
||||||
"invited_count": room_result.invited_count,
|
"invited_count": room_result.invited_count,
|
||||||
"notification_count": room_result.notification_count,
|
"notification_count": room_result.notification_count,
|
||||||
"highlight_count": room_result.highlight_count,
|
"highlight_count": room_result.highlight_count,
|
||||||
"num_live": room_result.num_live,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if room_result.name:
|
if room_result.name:
|
||||||
|
@ -1014,12 +996,47 @@ class SlidingSyncRestServlet(RestServlet):
|
||||||
if room_result.initial:
|
if room_result.initial:
|
||||||
serialized_rooms[room_id]["initial"] = room_result.initial
|
serialized_rooms[room_id]["initial"] = room_result.initial
|
||||||
|
|
||||||
|
# This will omitted for invite/knock rooms with `stripped_state`
|
||||||
|
if room_result.required_state is not None:
|
||||||
|
serialized_required_state = (
|
||||||
|
await self.event_serializer.serialize_events(
|
||||||
|
room_result.required_state,
|
||||||
|
time_now,
|
||||||
|
config=serialize_options,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
serialized_rooms[room_id]["required_state"] = serialized_required_state
|
||||||
|
|
||||||
|
# This will omitted for invite/knock rooms with `stripped_state`
|
||||||
|
if room_result.timeline_events is not None:
|
||||||
|
serialized_timeline = await self.event_serializer.serialize_events(
|
||||||
|
room_result.timeline_events,
|
||||||
|
time_now,
|
||||||
|
config=serialize_options,
|
||||||
|
bundle_aggregations=room_result.bundled_aggregations,
|
||||||
|
)
|
||||||
|
serialized_rooms[room_id]["timeline"] = serialized_timeline
|
||||||
|
|
||||||
|
# This will omitted for invite/knock rooms with `stripped_state`
|
||||||
|
if room_result.limited is not None:
|
||||||
|
serialized_rooms[room_id]["limited"] = room_result.limited
|
||||||
|
|
||||||
|
# This will omitted for invite/knock rooms with `stripped_state`
|
||||||
|
if room_result.prev_batch is not None:
|
||||||
|
serialized_rooms[room_id]["prev_batch"] = (
|
||||||
|
await room_result.prev_batch.to_string(self.store)
|
||||||
|
)
|
||||||
|
|
||||||
|
# This will omitted for invite/knock rooms with `stripped_state`
|
||||||
|
if room_result.num_live is not None:
|
||||||
|
serialized_rooms[room_id]["num_live"] = room_result.num_live
|
||||||
|
|
||||||
# Field should be absent on non-DM rooms
|
# Field should be absent on non-DM rooms
|
||||||
if room_result.is_dm:
|
if room_result.is_dm:
|
||||||
serialized_rooms[room_id]["is_dm"] = room_result.is_dm
|
serialized_rooms[room_id]["is_dm"] = room_result.is_dm
|
||||||
|
|
||||||
# Stripped state only applies to invite/knock rooms
|
# Stripped state only applies to invite/knock rooms
|
||||||
if room_result.stripped_state:
|
if room_result.stripped_state is not None:
|
||||||
# TODO: `knocked_state` but that isn't specced yet.
|
# TODO: `knocked_state` but that isn't specced yet.
|
||||||
#
|
#
|
||||||
# TODO: Instead of adding `knocked_state`, it would be good to rename
|
# TODO: Instead of adding `knocked_state`, it would be good to rename
|
||||||
|
|
|
@ -197,18 +197,23 @@ class SlidingSyncResult:
|
||||||
avatar: Optional[str]
|
avatar: Optional[str]
|
||||||
heroes: Optional[List[EventBase]]
|
heroes: Optional[List[EventBase]]
|
||||||
initial: bool
|
initial: bool
|
||||||
required_state: List[EventBase]
|
# Only optional because it won't be included for invite/knock rooms with `stripped_state`
|
||||||
timeline_events: List[EventBase]
|
required_state: Optional[List[EventBase]]
|
||||||
|
# Only optional because it won't be included for invite/knock rooms with `stripped_state`
|
||||||
|
timeline_events: Optional[List[EventBase]]
|
||||||
bundled_aggregations: Optional[Dict[str, "BundledAggregations"]]
|
bundled_aggregations: Optional[Dict[str, "BundledAggregations"]]
|
||||||
is_dm: bool
|
is_dm: bool
|
||||||
stripped_state: Optional[List[JsonDict]]
|
stripped_state: Optional[List[JsonDict]]
|
||||||
prev_batch: StreamToken
|
# Only optional because it won't be included for invite/knock rooms with `stripped_state`
|
||||||
limited: bool
|
prev_batch: Optional[StreamToken]
|
||||||
|
# Only optional because it won't be included for invite/knock rooms with `stripped_state`
|
||||||
|
limited: Optional[bool]
|
||||||
joined_count: int
|
joined_count: int
|
||||||
invited_count: int
|
invited_count: int
|
||||||
notification_count: int
|
notification_count: int
|
||||||
highlight_count: int
|
highlight_count: int
|
||||||
num_live: int
|
# Only optional because it won't be included for invite/knock rooms with `stripped_state`
|
||||||
|
num_live: Optional[int]
|
||||||
|
|
||||||
@attr.s(slots=True, frozen=True, auto_attribs=True)
|
@attr.s(slots=True, frozen=True, auto_attribs=True)
|
||||||
class SlidingWindowList:
|
class SlidingWindowList:
|
||||||
|
|
|
@ -1881,27 +1881,134 @@ class SlidingSyncTestCase(unittest.HomeserverTestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(channel.code, 200, channel.json_body)
|
self.assertEqual(channel.code, 200, channel.json_body)
|
||||||
|
|
||||||
# Should not see anything (except maybe the invite event) because we haven't
|
# `timeline` is omitted for `invite` rooms with `stripped_state`
|
||||||
# joined yet (history visibility is `shared`) (`filter_events_for_client(...)`
|
self.assertIsNone(
|
||||||
# is doing the work here)
|
channel.json_body["rooms"][room_id1].get("timeline"),
|
||||||
self.assertEqual(
|
|
||||||
channel.json_body["rooms"][room_id1]["timeline"],
|
|
||||||
[],
|
|
||||||
channel.json_body["rooms"][room_id1]["timeline"],
|
|
||||||
)
|
|
||||||
# No "live" events in an initial sync (no `from_token` to define the "live"
|
|
||||||
# range) and no events returned in the timeline anyway so nothing could be
|
|
||||||
# "live".
|
|
||||||
self.assertEqual(
|
|
||||||
channel.json_body["rooms"][room_id1]["num_live"],
|
|
||||||
0,
|
|
||||||
channel.json_body["rooms"][room_id1],
|
channel.json_body["rooms"][room_id1],
|
||||||
)
|
)
|
||||||
# Even though we don't get any timeline events because they are filtered out,
|
# `num_live` is omitted for `invite` rooms with `stripped_state` (no timeline anyway)
|
||||||
# there is still more to paginate
|
self.assertIsNone(
|
||||||
|
channel.json_body["rooms"][room_id1].get("num_live"),
|
||||||
|
channel.json_body["rooms"][room_id1],
|
||||||
|
)
|
||||||
|
# `limited` is omitted for `invite` rooms with `stripped_state` (no timeline anyway)
|
||||||
|
self.assertIsNone(
|
||||||
|
channel.json_body["rooms"][room_id1].get("limited"),
|
||||||
|
channel.json_body["rooms"][room_id1],
|
||||||
|
)
|
||||||
|
# `prev_batch` is omitted for `invite` rooms with `stripped_state` (no timeline anyway)
|
||||||
|
self.assertIsNone(
|
||||||
|
channel.json_body["rooms"][room_id1].get("prev_batch"),
|
||||||
|
channel.json_body["rooms"][room_id1],
|
||||||
|
)
|
||||||
|
# We should have some `stripped_state` so the potential joiner can identify the
|
||||||
|
# room (we don't care about the order).
|
||||||
|
self.assertCountEqual(
|
||||||
|
channel.json_body["rooms"][room_id1]["invite_state"],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"content": {"creator": user2_id, "room_version": "10"},
|
||||||
|
"sender": user2_id,
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.create",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {"join_rule": "public"},
|
||||||
|
"sender": user2_id,
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.join_rules",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {"displayname": user2.localpart, "membership": "join"},
|
||||||
|
"sender": user2_id,
|
||||||
|
"state_key": user2_id,
|
||||||
|
"type": "m.room.member",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": {"displayname": user1.localpart, "membership": "invite"},
|
||||||
|
"sender": user2_id,
|
||||||
|
"state_key": user1_id,
|
||||||
|
"type": "m.room.member",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
channel.json_body["rooms"][room_id1]["invite_state"],
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_rooms_invite_shared_history_incremental_sync(self) -> None:
|
||||||
|
"""
|
||||||
|
Test that `rooms` we are invited to have some stripped `invite_state`
|
||||||
|
|
||||||
|
This is an `invite` room so we should only have `stripped_state` (no timeline)
|
||||||
|
but we also shouldn't see any timeline events because the history visiblity is
|
||||||
|
`shared` and we haven't joined the room yet.
|
||||||
|
"""
|
||||||
|
user1_id = self.register_user("user1", "pass")
|
||||||
|
user1_tok = self.login(user1_id, "pass")
|
||||||
|
user1 = UserID.from_string(user1_id)
|
||||||
|
user2_id = self.register_user("user2", "pass")
|
||||||
|
user2_tok = self.login(user2_id, "pass")
|
||||||
|
user2 = UserID.from_string(user2_id)
|
||||||
|
|
||||||
|
room_id1 = self.helper.create_room_as(user2_id, tok=user2_tok)
|
||||||
|
# Ensure we're testing with a room with `shared` history visibility which means
|
||||||
|
# history visible until you actually join the room.
|
||||||
|
history_visibility_response = self.helper.get_state(
|
||||||
|
room_id1, EventTypes.RoomHistoryVisibility, tok=user2_tok
|
||||||
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
channel.json_body["rooms"][room_id1]["limited"],
|
history_visibility_response.get("history_visibility"),
|
||||||
True,
|
HistoryVisibility.SHARED,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.helper.send(room_id1, "activity before invite1", tok=user2_tok)
|
||||||
|
self.helper.send(room_id1, "activity before invite2", tok=user2_tok)
|
||||||
|
self.helper.invite(room_id1, src=user2_id, targ=user1_id, tok=user2_tok)
|
||||||
|
self.helper.send(room_id1, "activity after invite3", tok=user2_tok)
|
||||||
|
self.helper.send(room_id1, "activity after invite4", tok=user2_tok)
|
||||||
|
|
||||||
|
from_token = self.event_sources.get_current_token()
|
||||||
|
|
||||||
|
self.helper.send(room_id1, "activity after token5", tok=user2_tok)
|
||||||
|
self.helper.send(room_id1, "activity after toekn6", tok=user2_tok)
|
||||||
|
|
||||||
|
# Make the Sliding Sync request
|
||||||
|
channel = self.make_request(
|
||||||
|
"POST",
|
||||||
|
self.sync_endpoint
|
||||||
|
+ f"?pos={self.get_success(
|
||||||
|
from_token.to_string(self.store)
|
||||||
|
)}",
|
||||||
|
{
|
||||||
|
"lists": {
|
||||||
|
"foo-list": {
|
||||||
|
"ranges": [[0, 1]],
|
||||||
|
"required_state": [],
|
||||||
|
"timeline_limit": 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
access_token=user1_tok,
|
||||||
|
)
|
||||||
|
self.assertEqual(channel.code, 200, channel.json_body)
|
||||||
|
|
||||||
|
# `timeline` is omitted for `invite` rooms with `stripped_state`
|
||||||
|
self.assertIsNone(
|
||||||
|
channel.json_body["rooms"][room_id1].get("timeline"),
|
||||||
|
channel.json_body["rooms"][room_id1],
|
||||||
|
)
|
||||||
|
# `num_live` is omitted for `invite` rooms with `stripped_state` (no timeline anyway)
|
||||||
|
self.assertIsNone(
|
||||||
|
channel.json_body["rooms"][room_id1].get("num_live"),
|
||||||
|
channel.json_body["rooms"][room_id1],
|
||||||
|
)
|
||||||
|
# `limited` is omitted for `invite` rooms with `stripped_state` (no timeline anyway)
|
||||||
|
self.assertIsNone(
|
||||||
|
channel.json_body["rooms"][room_id1].get("limited"),
|
||||||
|
channel.json_body["rooms"][room_id1],
|
||||||
|
)
|
||||||
|
# `prev_batch` is omitted for `invite` rooms with `stripped_state` (no timeline anyway)
|
||||||
|
self.assertIsNone(
|
||||||
|
channel.json_body["rooms"][room_id1].get("prev_batch"),
|
||||||
channel.json_body["rooms"][room_id1],
|
channel.json_body["rooms"][room_id1],
|
||||||
)
|
)
|
||||||
# We should have some `stripped_state` so the potential joiner can identify the
|
# We should have some `stripped_state` so the potential joiner can identify the
|
||||||
|
@ -1977,12 +2084,10 @@ class SlidingSyncTestCase(unittest.HomeserverTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.helper.send(room_id1, "activity before1", tok=user2_tok)
|
self.helper.send(room_id1, "activity before1", tok=user2_tok)
|
||||||
event_response2 = self.helper.send(room_id1, "activity before2", tok=user2_tok)
|
self.helper.send(room_id1, "activity before2", tok=user2_tok)
|
||||||
use1_invite_response = self.helper.invite(
|
self.helper.invite(room_id1, src=user2_id, targ=user1_id, tok=user2_tok)
|
||||||
room_id1, src=user2_id, targ=user1_id, tok=user2_tok
|
self.helper.send(room_id1, "activity after3", tok=user2_tok)
|
||||||
)
|
self.helper.send(room_id1, "activity after4", tok=user2_tok)
|
||||||
event_response3 = self.helper.send(room_id1, "activity after3", tok=user2_tok)
|
|
||||||
event_response4 = self.helper.send(room_id1, "activity after4", tok=user2_tok)
|
|
||||||
|
|
||||||
# Make the Sliding Sync request
|
# Make the Sliding Sync request
|
||||||
channel = self.make_request(
|
channel = self.make_request(
|
||||||
|
@ -2002,31 +2107,24 @@ class SlidingSyncTestCase(unittest.HomeserverTestCase):
|
||||||
)
|
)
|
||||||
self.assertEqual(channel.code, 200, channel.json_body)
|
self.assertEqual(channel.code, 200, channel.json_body)
|
||||||
|
|
||||||
# Should see the last 4 events in the room
|
# `timeline` is omitted for `invite` rooms with `stripped_state`
|
||||||
self.assertEqual(
|
self.assertIsNone(
|
||||||
[
|
channel.json_body["rooms"][room_id1].get("timeline"),
|
||||||
event["event_id"]
|
|
||||||
for event in channel.json_body["rooms"][room_id1]["timeline"]
|
|
||||||
],
|
|
||||||
[
|
|
||||||
event_response2["event_id"],
|
|
||||||
use1_invite_response["event_id"],
|
|
||||||
event_response3["event_id"],
|
|
||||||
event_response4["event_id"],
|
|
||||||
],
|
|
||||||
channel.json_body["rooms"][room_id1]["timeline"],
|
|
||||||
)
|
|
||||||
# No "live" events in an initial sync (no `from_token` to define the "live"
|
|
||||||
# range)
|
|
||||||
self.assertEqual(
|
|
||||||
channel.json_body["rooms"][room_id1]["num_live"],
|
|
||||||
0,
|
|
||||||
channel.json_body["rooms"][room_id1],
|
channel.json_body["rooms"][room_id1],
|
||||||
)
|
)
|
||||||
# There is still more to paginate
|
# `num_live` is omitted for `invite` rooms with `stripped_state` (no timeline anyway)
|
||||||
self.assertEqual(
|
self.assertIsNone(
|
||||||
channel.json_body["rooms"][room_id1]["limited"],
|
channel.json_body["rooms"][room_id1].get("num_live"),
|
||||||
True,
|
channel.json_body["rooms"][room_id1],
|
||||||
|
)
|
||||||
|
# `limited` is omitted for `invite` rooms with `stripped_state` (no timeline anyway)
|
||||||
|
self.assertIsNone(
|
||||||
|
channel.json_body["rooms"][room_id1].get("limited"),
|
||||||
|
channel.json_body["rooms"][room_id1],
|
||||||
|
)
|
||||||
|
# `prev_batch` is omitted for `invite` rooms with `stripped_state` (no timeline anyway)
|
||||||
|
self.assertIsNone(
|
||||||
|
channel.json_body["rooms"][room_id1].get("prev_batch"),
|
||||||
channel.json_body["rooms"][room_id1],
|
channel.json_body["rooms"][room_id1],
|
||||||
)
|
)
|
||||||
# We should have some `stripped_state` so the potential joiner can identify the
|
# We should have some `stripped_state` so the potential joiner can identify the
|
||||||
|
|
Loading…
Reference in a new issue