forked from MirrorHub/synapse
Add search by room ID and room alias to List Room admin API (#11099)
Fixes: #10874 Signed-off-by: Dirk Klimpel dirk@klimpel.org
This commit is contained in:
parent
46d0937447
commit
7537201840
4 changed files with 76 additions and 53 deletions
1
changelog.d/11099.feature
Normal file
1
changelog.d/11099.feature
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Add search by room ID and room alias to List Room admin API.
|
|
@ -38,9 +38,14 @@ The following query parameters are available:
|
||||||
- `history_visibility` - Rooms are ordered alphabetically by visibility of history of the room.
|
- `history_visibility` - Rooms are ordered alphabetically by visibility of history of the room.
|
||||||
- `state_events` - Rooms are ordered by number of state events. Largest to smallest.
|
- `state_events` - Rooms are ordered by number of state events. Largest to smallest.
|
||||||
* `dir` - Direction of room order. Either `f` for forwards or `b` for backwards. Setting
|
* `dir` - Direction of room order. Either `f` for forwards or `b` for backwards. Setting
|
||||||
this value to `b` will reverse the above sort order. Defaults to `f`.
|
this value to `b` will reverse the above sort order. Defaults to `f`.
|
||||||
* `search_term` - Filter rooms by their room name. Search term can be contained in any
|
* `search_term` - Filter rooms by their room name, canonical alias and room id.
|
||||||
part of the room name. Defaults to no filtering.
|
Specifically, rooms are selected if the search term is contained in
|
||||||
|
- the room's name,
|
||||||
|
- the local part of the room's canonical alias, or
|
||||||
|
- the complete (local and server part) room's id (case sensitive).
|
||||||
|
|
||||||
|
Defaults to no filtering.
|
||||||
|
|
||||||
**Response**
|
**Response**
|
||||||
|
|
||||||
|
|
|
@ -412,22 +412,33 @@ class RoomWorkerStore(SQLBaseStore):
|
||||||
limit: maximum amount of rooms to retrieve
|
limit: maximum amount of rooms to retrieve
|
||||||
order_by: the sort order of the returned list
|
order_by: the sort order of the returned list
|
||||||
reverse_order: whether to reverse the room list
|
reverse_order: whether to reverse the room list
|
||||||
search_term: a string to filter room names by
|
search_term: a string to filter room names,
|
||||||
|
canonical alias and room ids by.
|
||||||
|
Room ID must match exactly. Canonical alias must match a substring of the local part.
|
||||||
Returns:
|
Returns:
|
||||||
A list of room dicts and an integer representing the total number of
|
A list of room dicts and an integer representing the total number of
|
||||||
rooms that exist given this query
|
rooms that exist given this query
|
||||||
"""
|
"""
|
||||||
# Filter room names by a string
|
# Filter room names by a string
|
||||||
where_statement = ""
|
where_statement = ""
|
||||||
|
search_pattern = []
|
||||||
if search_term:
|
if search_term:
|
||||||
where_statement = "WHERE LOWER(state.name) LIKE ?"
|
where_statement = """
|
||||||
|
WHERE LOWER(state.name) LIKE ?
|
||||||
|
OR LOWER(state.canonical_alias) LIKE ?
|
||||||
|
OR state.room_id = ?
|
||||||
|
"""
|
||||||
|
|
||||||
# Our postgres db driver converts ? -> %s in SQL strings as that's the
|
# Our postgres db driver converts ? -> %s in SQL strings as that's the
|
||||||
# placeholder for postgres.
|
# placeholder for postgres.
|
||||||
# HOWEVER, if you put a % into your SQL then everything goes wibbly.
|
# HOWEVER, if you put a % into your SQL then everything goes wibbly.
|
||||||
# To get around this, we're going to surround search_term with %'s
|
# To get around this, we're going to surround search_term with %'s
|
||||||
# before giving it to the database in python instead
|
# before giving it to the database in python instead
|
||||||
search_term = "%" + search_term.lower() + "%"
|
search_pattern = [
|
||||||
|
"%" + search_term.lower() + "%",
|
||||||
|
"#%" + search_term.lower() + "%:%",
|
||||||
|
search_term,
|
||||||
|
]
|
||||||
|
|
||||||
# Set ordering
|
# Set ordering
|
||||||
if RoomSortOrder(order_by) == RoomSortOrder.SIZE:
|
if RoomSortOrder(order_by) == RoomSortOrder.SIZE:
|
||||||
|
@ -519,12 +530,9 @@ class RoomWorkerStore(SQLBaseStore):
|
||||||
)
|
)
|
||||||
|
|
||||||
def _get_rooms_paginate_txn(txn):
|
def _get_rooms_paginate_txn(txn):
|
||||||
# Execute the data query
|
# Add the search term into the WHERE clause
|
||||||
sql_values = (limit, start)
|
# and execute the data query
|
||||||
if search_term:
|
txn.execute(info_sql, search_pattern + [limit, start])
|
||||||
# Add the search term into the WHERE clause
|
|
||||||
sql_values = (search_term,) + sql_values
|
|
||||||
txn.execute(info_sql, sql_values)
|
|
||||||
|
|
||||||
# Refactor room query data into a structured dictionary
|
# Refactor room query data into a structured dictionary
|
||||||
rooms = []
|
rooms = []
|
||||||
|
@ -551,8 +559,7 @@ class RoomWorkerStore(SQLBaseStore):
|
||||||
# Execute the count query
|
# Execute the count query
|
||||||
|
|
||||||
# Add the search term into the WHERE clause if present
|
# Add the search term into the WHERE clause if present
|
||||||
sql_values = (search_term,) if search_term else ()
|
txn.execute(count_sql, search_pattern)
|
||||||
txn.execute(count_sql, sql_values)
|
|
||||||
|
|
||||||
room_count = txn.fetchone()
|
room_count = txn.fetchone()
|
||||||
return rooms, room_count[0]
|
return rooms, room_count[0]
|
||||||
|
|
|
@ -680,36 +680,6 @@ class RoomTestCase(unittest.HomeserverTestCase):
|
||||||
reversing the order, etc.
|
reversing the order, etc.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _set_canonical_alias(room_id: str, test_alias: str, admin_user_tok: str):
|
|
||||||
# Create a new alias to this room
|
|
||||||
url = "/_matrix/client/r0/directory/room/%s" % (
|
|
||||||
urllib.parse.quote(test_alias),
|
|
||||||
)
|
|
||||||
channel = self.make_request(
|
|
||||||
"PUT",
|
|
||||||
url.encode("ascii"),
|
|
||||||
{"room_id": room_id},
|
|
||||||
access_token=admin_user_tok,
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
200, int(channel.result["code"]), msg=channel.result["body"]
|
|
||||||
)
|
|
||||||
|
|
||||||
# Set this new alias as the canonical alias for this room
|
|
||||||
self.helper.send_state(
|
|
||||||
room_id,
|
|
||||||
"m.room.aliases",
|
|
||||||
{"aliases": [test_alias]},
|
|
||||||
tok=admin_user_tok,
|
|
||||||
state_key="test",
|
|
||||||
)
|
|
||||||
self.helper.send_state(
|
|
||||||
room_id,
|
|
||||||
"m.room.canonical_alias",
|
|
||||||
{"alias": test_alias},
|
|
||||||
tok=admin_user_tok,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _order_test(
|
def _order_test(
|
||||||
order_type: str,
|
order_type: str,
|
||||||
expected_room_list: List[str],
|
expected_room_list: List[str],
|
||||||
|
@ -781,9 +751,9 @@ class RoomTestCase(unittest.HomeserverTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set room canonical room aliases
|
# Set room canonical room aliases
|
||||||
_set_canonical_alias(room_id_1, "#A_alias:test", self.admin_user_tok)
|
self._set_canonical_alias(room_id_1, "#A_alias:test", self.admin_user_tok)
|
||||||
_set_canonical_alias(room_id_2, "#B_alias:test", self.admin_user_tok)
|
self._set_canonical_alias(room_id_2, "#B_alias:test", self.admin_user_tok)
|
||||||
_set_canonical_alias(room_id_3, "#C_alias:test", self.admin_user_tok)
|
self._set_canonical_alias(room_id_3, "#C_alias:test", self.admin_user_tok)
|
||||||
|
|
||||||
# Set room member size in the reverse order. room 1 -> 1 member, 2 -> 2, 3 -> 3
|
# Set room member size in the reverse order. room 1 -> 1 member, 2 -> 2, 3 -> 3
|
||||||
user_1 = self.register_user("bob1", "pass")
|
user_1 = self.register_user("bob1", "pass")
|
||||||
|
@ -850,7 +820,7 @@ class RoomTestCase(unittest.HomeserverTestCase):
|
||||||
room_id_2 = self.helper.create_room_as(self.admin_user, tok=self.admin_user_tok)
|
room_id_2 = self.helper.create_room_as(self.admin_user, tok=self.admin_user_tok)
|
||||||
|
|
||||||
room_name_1 = "something"
|
room_name_1 = "something"
|
||||||
room_name_2 = "else"
|
room_name_2 = "LoremIpsum"
|
||||||
|
|
||||||
# Set the name for each room
|
# Set the name for each room
|
||||||
self.helper.send_state(
|
self.helper.send_state(
|
||||||
|
@ -866,6 +836,8 @@ class RoomTestCase(unittest.HomeserverTestCase):
|
||||||
tok=self.admin_user_tok,
|
tok=self.admin_user_tok,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self._set_canonical_alias(room_id_1, "#Room_Alias1:test", self.admin_user_tok)
|
||||||
|
|
||||||
def _search_test(
|
def _search_test(
|
||||||
expected_room_id: Optional[str],
|
expected_room_id: Optional[str],
|
||||||
search_term: str,
|
search_term: str,
|
||||||
|
@ -914,24 +886,36 @@ class RoomTestCase(unittest.HomeserverTestCase):
|
||||||
r = rooms[0]
|
r = rooms[0]
|
||||||
self.assertEqual(expected_room_id, r["room_id"])
|
self.assertEqual(expected_room_id, r["room_id"])
|
||||||
|
|
||||||
# Perform search tests
|
# Test searching by room name
|
||||||
_search_test(room_id_1, "something")
|
_search_test(room_id_1, "something")
|
||||||
_search_test(room_id_1, "thing")
|
_search_test(room_id_1, "thing")
|
||||||
|
|
||||||
_search_test(room_id_2, "else")
|
_search_test(room_id_2, "LoremIpsum")
|
||||||
_search_test(room_id_2, "se")
|
_search_test(room_id_2, "lorem")
|
||||||
|
|
||||||
# Test case insensitive
|
# Test case insensitive
|
||||||
_search_test(room_id_1, "SOMETHING")
|
_search_test(room_id_1, "SOMETHING")
|
||||||
_search_test(room_id_1, "THING")
|
_search_test(room_id_1, "THING")
|
||||||
|
|
||||||
_search_test(room_id_2, "ELSE")
|
_search_test(room_id_2, "LOREMIPSUM")
|
||||||
_search_test(room_id_2, "SE")
|
_search_test(room_id_2, "LOREM")
|
||||||
|
|
||||||
_search_test(None, "foo")
|
_search_test(None, "foo")
|
||||||
_search_test(None, "bar")
|
_search_test(None, "bar")
|
||||||
_search_test(None, "", expected_http_code=400)
|
_search_test(None, "", expected_http_code=400)
|
||||||
|
|
||||||
|
# Test that the whole room id returns the room
|
||||||
|
_search_test(room_id_1, room_id_1)
|
||||||
|
# Test that the search by room_id is case sensitive
|
||||||
|
_search_test(None, room_id_1.lower())
|
||||||
|
# Test search part of local part of room id do not match
|
||||||
|
_search_test(None, room_id_1[1:10])
|
||||||
|
|
||||||
|
# Test that whole room alias return no result, because of domain
|
||||||
|
_search_test(None, "#Room_Alias1:test")
|
||||||
|
# Test search local part of alias
|
||||||
|
_search_test(room_id_1, "alias1")
|
||||||
|
|
||||||
def test_search_term_non_ascii(self):
|
def test_search_term_non_ascii(self):
|
||||||
"""Test that searching for a room with non-ASCII characters works correctly"""
|
"""Test that searching for a room with non-ASCII characters works correctly"""
|
||||||
|
|
||||||
|
@ -1114,6 +1098,32 @@ class RoomTestCase(unittest.HomeserverTestCase):
|
||||||
# the create_room already does the right thing, so no need to verify that we got
|
# the create_room already does the right thing, so no need to verify that we got
|
||||||
# the state events it created.
|
# the state events it created.
|
||||||
|
|
||||||
|
def _set_canonical_alias(self, room_id: str, test_alias: str, admin_user_tok: str):
|
||||||
|
# Create a new alias to this room
|
||||||
|
url = "/_matrix/client/r0/directory/room/%s" % (urllib.parse.quote(test_alias),)
|
||||||
|
channel = self.make_request(
|
||||||
|
"PUT",
|
||||||
|
url.encode("ascii"),
|
||||||
|
{"room_id": room_id},
|
||||||
|
access_token=admin_user_tok,
|
||||||
|
)
|
||||||
|
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
|
||||||
|
|
||||||
|
# Set this new alias as the canonical alias for this room
|
||||||
|
self.helper.send_state(
|
||||||
|
room_id,
|
||||||
|
"m.room.aliases",
|
||||||
|
{"aliases": [test_alias]},
|
||||||
|
tok=admin_user_tok,
|
||||||
|
state_key="test",
|
||||||
|
)
|
||||||
|
self.helper.send_state(
|
||||||
|
room_id,
|
||||||
|
"m.room.canonical_alias",
|
||||||
|
{"alias": test_alias},
|
||||||
|
tok=admin_user_tok,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class JoinAliasRoomTestCase(unittest.HomeserverTestCase):
|
class JoinAliasRoomTestCase(unittest.HomeserverTestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue