Skip to content

Commit

Permalink
SS: Implement $ME support (#17469)
Browse files Browse the repository at this point in the history
`$ME` can be used as a substitute for the requester's user ID.
  • Loading branch information
erikjohnston authored Jul 22, 2024
1 parent ed0face commit d221512
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 1 deletion.
1 change: 1 addition & 0 deletions changelog.d/17469.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implement handling of `$ME` as a state key in sliding sync.
6 changes: 5 additions & 1 deletion synapse/handlers/sliding_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,9 @@ class StateValues:
# `sender` in the timeline). We only give special meaning to this value when it's a
# `state_key`.
LAZY: Final = "$LAZY"
# Subsitute with the requester's user ID. Typically used by clients to get
# the user's membership.
ME: Final = "$ME"


class SlidingSyncHandler:
Expand Down Expand Up @@ -504,7 +507,6 @@ async def current_sync_for_user(
# Also see `StateFilter.must_await_full_state(...)` for comparison
lazy_loading = (
membership_state_keys is not None
and len(membership_state_keys) == 1
and StateValues.LAZY in membership_state_keys
)

Expand Down Expand Up @@ -1662,6 +1664,8 @@ async def get_room_sync_data(

# FIXME: We probably also care about invite, ban, kick, targets, etc
# but the spec only mentions "senders".
elif state_key == StateValues.ME:
required_state_types.append((state_type, user.to_string()))
else:
required_state_types.append((state_type, state_key))

Expand Down
74 changes: 74 additions & 0 deletions tests/rest/client/test_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -3714,6 +3714,80 @@ def test_rooms_required_state_lazy_loading_room_members(self) -> None:
)
self.assertIsNone(channel.json_body["rooms"][room_id1].get("invite_state"))

def test_rooms_required_state_me(self) -> None:
"""
Test `rooms.required_state` correctly handles $ME.
"""
user1_id = self.register_user("user1", "pass")
user1_tok = self.login(user1_id, "pass")
user2_id = self.register_user("user2", "pass")
user2_tok = self.login(user2_id, "pass")

room_id1 = self.helper.create_room_as(user2_id, tok=user2_tok)
self.helper.join(room_id1, user1_id, tok=user1_tok)

self.helper.send(room_id1, "1", tok=user2_tok)

# Also send normal state events with state keys of the users, first
# change the power levels to allow this.
self.helper.send_state(
room_id1,
event_type=EventTypes.PowerLevels,
body={"users": {user1_id: 50, user2_id: 100}},
tok=user2_tok,
)
self.helper.send_state(
room_id1,
event_type="org.matrix.foo",
state_key=user1_id,
body={},
tok=user1_tok,
)
self.helper.send_state(
room_id1,
event_type="org.matrix.foo",
state_key=user2_id,
body={},
tok=user2_tok,
)

# Make the Sliding Sync request with a request for '$ME'.
channel = self.make_request(
"POST",
self.sync_endpoint,
{
"lists": {
"foo-list": {
"ranges": [[0, 1]],
"required_state": [
[EventTypes.Create, ""],
[EventTypes.Member, StateValues.ME],
["org.matrix.foo", StateValues.ME],
],
"timeline_limit": 3,
}
}
},
access_token=user1_tok,
)
self.assertEqual(channel.code, 200, channel.json_body)

state_map = self.get_success(
self.storage_controllers.state.get_current_state(room_id1)
)

# Only user2 and user3 sent events in the 3 events we see in the `timeline`
self._assertRequiredStateIncludes(
channel.json_body["rooms"][room_id1]["required_state"],
{
state_map[(EventTypes.Create, "")],
state_map[(EventTypes.Member, user1_id)],
state_map[("org.matrix.foo", user1_id)],
},
exact=True,
)
self.assertIsNone(channel.json_body["rooms"][room_id1].get("invite_state"))

@parameterized.expand([(Membership.LEAVE,), (Membership.BAN,)])
def test_rooms_required_state_leave_ban(self, stop_membership: str) -> None:
"""
Expand Down

0 comments on commit d221512

Please sign in to comment.