Filter by room_types/not_room_types

This commit is contained in:
Eric Eastwood 2024-06-19 18:30:16 -05:00
parent cf285ca800
commit fe77f4fae9
3 changed files with 231 additions and 7 deletions

View file

@ -605,14 +605,26 @@ class SlidingSyncHandler:
if filters.is_invite: if filters.is_invite:
raise NotImplementedError() raise NotImplementedError()
if filters.room_types is not None: # Filter by room type (space vs room, etc). A room must match one of the types
# provided in the list. `None` is a valid type for rooms which do not have a
# room type.
if filters.room_types is not None or filters.not_room_types is not None:
# Make a copy so we don't run into an error: `Set changed size during
# iteration`, when we filter out and remove items
for room_id in list(filtered_room_id_set): for room_id in list(filtered_room_id_set):
create_event = await self.store.get_create_event_for_room(room_id) create_event = await self.store.get_create_event_for_room(room_id)
room_type = create_event.content.get(EventContentFields.ROOM_TYPE)
if (
filters.room_types is not None
and room_type not in filters.room_types
):
filtered_room_id_set.remove(room_id)
create_event.content.get(EventContentFields.ROOM_TYPE) if (
filters.not_room_types is not None
if filters.not_room_types: and room_type in filters.not_room_types
raise NotImplementedError() ):
filtered_room_id_set.remove(room_id)
if filters.room_name_like: if filters.room_name_like:
raise NotImplementedError() raise NotImplementedError()

View file

@ -270,7 +270,7 @@ class SlidingSyncBody(RequestBodyModel):
is_encrypted: Optional[StrictBool] = None is_encrypted: Optional[StrictBool] = None
is_invite: Optional[StrictBool] = None is_invite: Optional[StrictBool] = None
room_types: Optional[List[Union[StrictStr, None]]] = None room_types: Optional[List[Union[StrictStr, None]]] = None
not_room_types: Optional[List[StrictStr]] = None not_room_types: Optional[List[Union[StrictStr, None]]] = None
room_name_like: Optional[StrictStr] = None room_name_like: Optional[StrictStr] = None
tags: Optional[List[StrictStr]] = None tags: Optional[List[StrictStr]] = None
not_tags: Optional[List[StrictStr]] = None not_tags: Optional[List[StrictStr]] = None

View file

@ -24,7 +24,14 @@ from parameterized import parameterized
from twisted.test.proto_helpers import MemoryReactor from twisted.test.proto_helpers import MemoryReactor
from synapse.api.constants import AccountDataTypes, EventTypes, JoinRules, Membership from synapse.api.constants import (
AccountDataTypes,
EventContentFields,
EventTypes,
JoinRules,
Membership,
RoomTypes,
)
from synapse.api.room_versions import RoomVersions from synapse.api.room_versions import RoomVersions
from synapse.handlers.sliding_sync import SlidingSyncConfig from synapse.handlers.sliding_sync import SlidingSyncConfig
from synapse.rest import admin from synapse.rest import admin
@ -1319,6 +1326,211 @@ class FilterRoomsTestCase(HomeserverTestCase):
self.assertEqual(falsy_filtered_room_map.keys(), {room_id}) self.assertEqual(falsy_filtered_room_map.keys(), {room_id})
def test_filter_room_types(self) -> None:
"""
Test `filter.room_types` for different room types
"""
user1_id = self.register_user("user1", "pass")
user1_tok = self.login(user1_id, "pass")
# Create a normal room (no room type)
room_id = self.helper.create_room_as(user1_id, tok=user1_tok)
# Create a space room
space_room_id = self.helper.create_room_as(
user1_id,
tok=user1_tok,
extra_content={
"creation_content": {EventContentFields.ROOM_TYPE: RoomTypes.SPACE}
},
)
# Create an arbitrarily typed room
foo_room_id = self.helper.create_room_as(
user1_id,
tok=user1_tok,
extra_content={
"creation_content": {
EventContentFields.ROOM_TYPE: "org.matrix.foobarbaz"
}
},
)
after_rooms_token = self.event_sources.get_current_token()
# Get the rooms the user should be syncing with
sync_room_map = self.get_success(
self.sliding_sync_handler.get_sync_room_ids_for_user(
UserID.from_string(user1_id),
from_token=None,
to_token=after_rooms_token,
)
)
# Try finding only normal rooms
filtered_room_map = self.get_success(
self.sliding_sync_handler.filter_rooms(
UserID.from_string(user1_id),
sync_room_map,
SlidingSyncConfig.SlidingSyncList.Filters(room_types=[None]),
after_rooms_token,
)
)
self.assertEqual(filtered_room_map.keys(), {room_id})
# Try finding only spaces
filtered_room_map = self.get_success(
self.sliding_sync_handler.filter_rooms(
UserID.from_string(user1_id),
sync_room_map,
SlidingSyncConfig.SlidingSyncList.Filters(room_types=[RoomTypes.SPACE]),
after_rooms_token,
)
)
self.assertEqual(filtered_room_map.keys(), {space_room_id})
# Try finding normal rooms and spaces
filtered_room_map = self.get_success(
self.sliding_sync_handler.filter_rooms(
UserID.from_string(user1_id),
sync_room_map,
SlidingSyncConfig.SlidingSyncList.Filters(
room_types=[None, RoomTypes.SPACE]
),
after_rooms_token,
)
)
self.assertEqual(filtered_room_map.keys(), {room_id, space_room_id})
# Try finding an arbitrary room type
filtered_room_map = self.get_success(
self.sliding_sync_handler.filter_rooms(
UserID.from_string(user1_id),
sync_room_map,
SlidingSyncConfig.SlidingSyncList.Filters(
room_types=["org.matrix.foobarbaz"]
),
after_rooms_token,
)
)
self.assertEqual(filtered_room_map.keys(), {foo_room_id})
def test_filter_not_room_types(self) -> None:
"""
Test `filter.not_room_types` for different room types
"""
user1_id = self.register_user("user1", "pass")
user1_tok = self.login(user1_id, "pass")
# Create a normal room (no room type)
room_id = self.helper.create_room_as(user1_id, tok=user1_tok)
# Create a space room
space_room_id = self.helper.create_room_as(
user1_id,
tok=user1_tok,
extra_content={
"creation_content": {EventContentFields.ROOM_TYPE: RoomTypes.SPACE}
},
)
# Create an arbitrarily typed room
foo_room_id = self.helper.create_room_as(
user1_id,
tok=user1_tok,
extra_content={
"creation_content": {
EventContentFields.ROOM_TYPE: "org.matrix.foobarbaz"
}
},
)
after_rooms_token = self.event_sources.get_current_token()
# Get the rooms the user should be syncing with
sync_room_map = self.get_success(
self.sliding_sync_handler.get_sync_room_ids_for_user(
UserID.from_string(user1_id),
from_token=None,
to_token=after_rooms_token,
)
)
# Try finding *NOT* normal rooms
filtered_room_map = self.get_success(
self.sliding_sync_handler.filter_rooms(
UserID.from_string(user1_id),
sync_room_map,
SlidingSyncConfig.SlidingSyncList.Filters(not_room_types=[None]),
after_rooms_token,
)
)
self.assertEqual(filtered_room_map.keys(), {space_room_id, foo_room_id})
# Try finding *NOT* spaces
filtered_room_map = self.get_success(
self.sliding_sync_handler.filter_rooms(
UserID.from_string(user1_id),
sync_room_map,
SlidingSyncConfig.SlidingSyncList.Filters(
not_room_types=[RoomTypes.SPACE]
),
after_rooms_token,
)
)
self.assertEqual(filtered_room_map.keys(), {room_id, foo_room_id})
# Try finding *NOT* normal rooms or spaces
filtered_room_map = self.get_success(
self.sliding_sync_handler.filter_rooms(
UserID.from_string(user1_id),
sync_room_map,
SlidingSyncConfig.SlidingSyncList.Filters(
not_room_types=[None, RoomTypes.SPACE]
),
after_rooms_token,
)
)
self.assertEqual(filtered_room_map.keys(), {foo_room_id})
# Test how it behaves when we have both `room_types` and `not_room_types`.
# `not_room_types` should win.
filtered_room_map = self.get_success(
self.sliding_sync_handler.filter_rooms(
UserID.from_string(user1_id),
sync_room_map,
SlidingSyncConfig.SlidingSyncList.Filters(
room_types=[None], not_room_types=[None]
),
after_rooms_token,
)
)
# Nothing matches because nothing is both a normal room and not a normal room
self.assertEqual(filtered_room_map.keys(), set())
# Test how it behaves when we have both `room_types` and `not_room_types`.
# `not_room_types` should win.
filtered_room_map = self.get_success(
self.sliding_sync_handler.filter_rooms(
UserID.from_string(user1_id),
sync_room_map,
SlidingSyncConfig.SlidingSyncList.Filters(
room_types=[None, RoomTypes.SPACE], not_room_types=[None]
),
after_rooms_token,
)
)
self.assertEqual(filtered_room_map.keys(), {space_room_id})
class SortRoomsTestCase(HomeserverTestCase): class SortRoomsTestCase(HomeserverTestCase):
""" """