Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 0b037d6

Browse files
authored
Fix handling of public rooms filter with a network tuple. (#14053)
Fixes two related bugs: * The handling of `[null]` for a `room_types` filter was incorrect. * The ordering of arguments when providing both a network tuple and room type field was incorrect.
1 parent dcced5a commit 0b037d6

File tree

3 files changed

+58
-27
lines changed

3 files changed

+58
-27
lines changed

changelog.d/14053.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a bug introduced in Synapse 1.53.0 when querying `/publicRooms` with both a `room_type` filter and a `third_party_instance_id`.

synapse/storage/databases/main/room.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -207,21 +207,30 @@ async def get_public_room_ids(self) -> List[str]:
207207

208208
def _construct_room_type_where_clause(
209209
self, room_types: Union[List[Union[str, None]], None]
210-
) -> Tuple[Union[str, None], List[str]]:
210+
) -> Tuple[Union[str, None], list]:
211211
if not room_types:
212212
return None, []
213-
else:
214-
# We use None when we want get rooms without a type
215-
is_null_clause = ""
216-
if None in room_types:
217-
is_null_clause = "OR room_type IS NULL"
218-
room_types = [value for value in room_types if value is not None]
219213

214+
# Since None is used to represent a room without a type, care needs to
215+
# be taken into account when constructing the where clause.
216+
clauses = []
217+
args: list = []
218+
219+
room_types_set = set(room_types)
220+
221+
# We use None to represent a room without a type.
222+
if None in room_types_set:
223+
clauses.append("room_type IS NULL")
224+
room_types_set.remove(None)
225+
226+
# If there are other room types, generate the proper clause.
227+
if room_types:
220228
list_clause, args = make_in_list_sql_clause(
221-
self.database_engine, "room_type", room_types
229+
self.database_engine, "room_type", room_types_set
222230
)
231+
clauses.append(list_clause)
223232

224-
return f"({list_clause} {is_null_clause})", args
233+
return f"({' OR '.join(clauses)})", args
225234

226235
async def count_public_rooms(
227236
self,
@@ -241,14 +250,6 @@ async def count_public_rooms(
241250
def _count_public_rooms_txn(txn: LoggingTransaction) -> int:
242251
query_args = []
243252

244-
room_type_clause, args = self._construct_room_type_where_clause(
245-
search_filter.get(PublicRoomsFilterFields.ROOM_TYPES, None)
246-
if search_filter
247-
else None
248-
)
249-
room_type_clause = f" AND {room_type_clause}" if room_type_clause else ""
250-
query_args += args
251-
252253
if network_tuple:
253254
if network_tuple.appservice_id:
254255
published_sql = """
@@ -268,6 +269,14 @@ def _count_public_rooms_txn(txn: LoggingTransaction) -> int:
268269
UNION SELECT room_id from appservice_room_list
269270
"""
270271

272+
room_type_clause, args = self._construct_room_type_where_clause(
273+
search_filter.get(PublicRoomsFilterFields.ROOM_TYPES, None)
274+
if search_filter
275+
else None
276+
)
277+
room_type_clause = f" AND {room_type_clause}" if room_type_clause else ""
278+
query_args += args
279+
271280
sql = f"""
272281
SELECT
273282
COUNT(*)

tests/rest/client/test_rooms.py

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2213,14 +2213,17 @@ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
22132213
)
22142214

22152215
def make_public_rooms_request(
2216-
self, room_types: Union[List[Union[str, None]], None]
2216+
self,
2217+
room_types: Optional[List[Union[str, None]]],
2218+
instance_id: Optional[str] = None,
22172219
) -> Tuple[List[Dict[str, Any]], int]:
2218-
channel = self.make_request(
2219-
"POST",
2220-
self.url,
2221-
{"filter": {PublicRoomsFilterFields.ROOM_TYPES: room_types}},
2222-
self.token,
2223-
)
2220+
body: JsonDict = {"filter": {PublicRoomsFilterFields.ROOM_TYPES: room_types}}
2221+
if instance_id:
2222+
body["third_party_instance_id"] = "test|test"
2223+
2224+
channel = self.make_request("POST", self.url, body, self.token)
2225+
self.assertEqual(channel.code, 200)
2226+
22242227
chunk = channel.json_body["chunk"]
22252228
count = channel.json_body["total_room_count_estimate"]
22262229

@@ -2230,31 +2233,49 @@ def make_public_rooms_request(
22302233

22312234
def test_returns_both_rooms_and_spaces_if_no_filter(self) -> None:
22322235
chunk, count = self.make_public_rooms_request(None)
2233-
22342236
self.assertEqual(count, 2)
22352237

2238+
# Also check if there's no filter property at all in the body.
2239+
channel = self.make_request("POST", self.url, {}, self.token)
2240+
self.assertEqual(channel.code, 200)
2241+
self.assertEqual(len(channel.json_body["chunk"]), 2)
2242+
self.assertEqual(channel.json_body["total_room_count_estimate"], 2)
2243+
2244+
chunk, count = self.make_public_rooms_request(None, "test|test")
2245+
self.assertEqual(count, 0)
2246+
22362247
def test_returns_only_rooms_based_on_filter(self) -> None:
22372248
chunk, count = self.make_public_rooms_request([None])
22382249

22392250
self.assertEqual(count, 1)
22402251
self.assertEqual(chunk[0].get("room_type", None), None)
22412252

2253+
chunk, count = self.make_public_rooms_request([None], "test|test")
2254+
self.assertEqual(count, 0)
2255+
22422256
def test_returns_only_space_based_on_filter(self) -> None:
22432257
chunk, count = self.make_public_rooms_request(["m.space"])
22442258

22452259
self.assertEqual(count, 1)
22462260
self.assertEqual(chunk[0].get("room_type", None), "m.space")
22472261

2262+
chunk, count = self.make_public_rooms_request(["m.space"], "test|test")
2263+
self.assertEqual(count, 0)
2264+
22482265
def test_returns_both_rooms_and_space_based_on_filter(self) -> None:
22492266
chunk, count = self.make_public_rooms_request(["m.space", None])
2250-
22512267
self.assertEqual(count, 2)
22522268

2269+
chunk, count = self.make_public_rooms_request(["m.space", None], "test|test")
2270+
self.assertEqual(count, 0)
2271+
22532272
def test_returns_both_rooms_and_spaces_if_array_is_empty(self) -> None:
22542273
chunk, count = self.make_public_rooms_request([])
2255-
22562274
self.assertEqual(count, 2)
22572275

2276+
chunk, count = self.make_public_rooms_request([], "test|test")
2277+
self.assertEqual(count, 0)
2278+
22582279

22592280
class PublicRoomsTestRemoteSearchFallbackTestCase(unittest.HomeserverTestCase):
22602281
"""Test that we correctly fallback to local filtering if a remote server

0 commit comments

Comments
 (0)