Add the ability to exclude remote users in user directory search results (#18300)
This change adds a new configuration `user_directory.exclude_remote_users`, which defaults to False. When set to True, remote users will not appear in user directory search results. ### Pull Request Checklist <!-- Please read https://element-hq.github.io/synapse/latest/development/contributing_guide.html before submitting your pull request --> * [x] Pull request is based on the develop branch * [x] Pull request includes a [changelog file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog). The entry should: - Be a short description of your change which makes sense to users. "Fixed a bug that prevented receiving messages from other servers." instead of "Moved X method from `EventStore` to `EventWorkerStore`.". - Use markdown where necessary, mostly for `code blocks`. - End with either a period (.) or an exclamation mark (!). - Start with a capital letter. - Feel free to credit yourself, by adding a sentence "Contributed by @github_username." or "Contributed by [Your Name]." to the end of the entry. * [x] [Code style](https://element-hq.github.io/synapse/latest/code_style.html) is correct (run the [linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters)) --------- Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
This commit is contained in:
parent
b8146d4b03
commit
fe8bb620de
1
changelog.d/18300.feature
Normal file
1
changelog.d/18300.feature
Normal file
@ -0,0 +1 @@
|
||||
Add config option `user_directory.exclude_remote_users` which, when enabled, excludes remote users from user directory search results.
|
||||
@ -4095,6 +4095,7 @@ This option has the following sub-options:
|
||||
* `prefer_local_users`: Defines whether to prefer local users in search query results.
|
||||
If set to true, local users are more likely to appear above remote users when searching the
|
||||
user directory. Defaults to false.
|
||||
* `exclude_remote_users`: If set to true, the search will only return local users. Defaults to false.
|
||||
* `show_locked_users`: Defines whether to show locked users in search query results. Defaults to false.
|
||||
|
||||
Example configuration:
|
||||
@ -4103,6 +4104,7 @@ user_directory:
|
||||
enabled: false
|
||||
search_all_users: true
|
||||
prefer_local_users: true
|
||||
exclude_remote_users: false
|
||||
show_locked_users: true
|
||||
```
|
||||
---
|
||||
|
||||
@ -38,6 +38,9 @@ class UserDirectoryConfig(Config):
|
||||
self.user_directory_search_all_users = user_directory_config.get(
|
||||
"search_all_users", False
|
||||
)
|
||||
self.user_directory_exclude_remote_users = user_directory_config.get(
|
||||
"exclude_remote_users", False
|
||||
)
|
||||
self.user_directory_search_prefer_local_users = user_directory_config.get(
|
||||
"prefer_local_users", False
|
||||
)
|
||||
|
||||
@ -108,6 +108,9 @@ class UserDirectoryHandler(StateDeltasHandler):
|
||||
self.is_mine_id = hs.is_mine_id
|
||||
self.update_user_directory = hs.config.worker.should_update_user_directory
|
||||
self.search_all_users = hs.config.userdirectory.user_directory_search_all_users
|
||||
self.exclude_remote_users = (
|
||||
hs.config.userdirectory.user_directory_exclude_remote_users
|
||||
)
|
||||
self.show_locked_users = hs.config.userdirectory.show_locked_users
|
||||
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
|
||||
self._hs = hs
|
||||
|
||||
@ -1037,11 +1037,11 @@ class UserDirectoryStore(UserDirectoryBackgroundUpdateStore):
|
||||
}
|
||||
"""
|
||||
|
||||
join_args: Tuple[str, ...] = (user_id,)
|
||||
|
||||
if self.hs.config.userdirectory.user_directory_search_all_users:
|
||||
join_args = (user_id,)
|
||||
where_clause = "user_id != ?"
|
||||
else:
|
||||
join_args = (user_id,)
|
||||
where_clause = """
|
||||
(
|
||||
EXISTS (select 1 from users_in_public_rooms WHERE user_id = t.user_id)
|
||||
@ -1055,6 +1055,14 @@ class UserDirectoryStore(UserDirectoryBackgroundUpdateStore):
|
||||
if not show_locked_users:
|
||||
where_clause += " AND (u.locked IS NULL OR u.locked = FALSE)"
|
||||
|
||||
# Adjust the JOIN type based on the exclude_remote_users flag (the users
|
||||
# table only contains local users so an inner join is a good way to
|
||||
# to exclude remote users)
|
||||
if self.hs.config.userdirectory.user_directory_exclude_remote_users:
|
||||
join_type = "JOIN"
|
||||
else:
|
||||
join_type = "LEFT JOIN"
|
||||
|
||||
# We allow manipulating the ranking algorithm by injecting statements
|
||||
# based on config options.
|
||||
additional_ordering_statements = []
|
||||
@ -1086,7 +1094,7 @@ class UserDirectoryStore(UserDirectoryBackgroundUpdateStore):
|
||||
SELECT d.user_id AS user_id, display_name, avatar_url
|
||||
FROM matching_users as t
|
||||
INNER JOIN user_directory AS d USING (user_id)
|
||||
LEFT JOIN users AS u ON t.user_id = u.name
|
||||
%(join_type)s users AS u ON t.user_id = u.name
|
||||
WHERE
|
||||
%(where_clause)s
|
||||
ORDER BY
|
||||
@ -1115,6 +1123,7 @@ class UserDirectoryStore(UserDirectoryBackgroundUpdateStore):
|
||||
""" % {
|
||||
"where_clause": where_clause,
|
||||
"order_case_statements": " ".join(additional_ordering_statements),
|
||||
"join_type": join_type,
|
||||
}
|
||||
args = (
|
||||
(full_query,)
|
||||
@ -1142,7 +1151,7 @@ class UserDirectoryStore(UserDirectoryBackgroundUpdateStore):
|
||||
SELECT d.user_id AS user_id, display_name, avatar_url
|
||||
FROM user_directory_search as t
|
||||
INNER JOIN user_directory AS d USING (user_id)
|
||||
LEFT JOIN users AS u ON t.user_id = u.name
|
||||
%(join_type)s users AS u ON t.user_id = u.name
|
||||
WHERE
|
||||
%(where_clause)s
|
||||
AND value MATCH ?
|
||||
@ -1155,6 +1164,7 @@ class UserDirectoryStore(UserDirectoryBackgroundUpdateStore):
|
||||
""" % {
|
||||
"where_clause": where_clause,
|
||||
"order_statements": " ".join(additional_ordering_statements),
|
||||
"join_type": join_type,
|
||||
}
|
||||
args = join_args + (search_query,) + ordering_arguments + (limit + 1,)
|
||||
else:
|
||||
|
||||
@ -992,6 +992,67 @@ class UserDirectoryTestCase(unittest.HomeserverTestCase):
|
||||
[self.assertIn(user, local_users) for user in received_user_id_ordering[:3]]
|
||||
[self.assertIn(user, remote_users) for user in received_user_id_ordering[3:]]
|
||||
|
||||
@override_config(
|
||||
{
|
||||
"user_directory": {
|
||||
"enabled": True,
|
||||
"search_all_users": True,
|
||||
"exclude_remote_users": True,
|
||||
}
|
||||
}
|
||||
)
|
||||
def test_exclude_remote_users(self) -> None:
|
||||
"""Tests that only local users are returned when
|
||||
user_directory.exclude_remote_users is True.
|
||||
"""
|
||||
|
||||
# Create a room and few users to test the directory with
|
||||
searching_user = self.register_user("searcher", "password")
|
||||
searching_user_tok = self.login("searcher", "password")
|
||||
|
||||
room_id = self.helper.create_room_as(
|
||||
searching_user,
|
||||
room_version=RoomVersions.V1.identifier,
|
||||
tok=searching_user_tok,
|
||||
)
|
||||
|
||||
# Create a few local users and join them to the room
|
||||
local_user_1 = self.register_user("user_xxxxx", "password")
|
||||
local_user_2 = self.register_user("user_bbbbb", "password")
|
||||
local_user_3 = self.register_user("user_zzzzz", "password")
|
||||
|
||||
self._add_user_to_room(room_id, RoomVersions.V1, local_user_1)
|
||||
self._add_user_to_room(room_id, RoomVersions.V1, local_user_2)
|
||||
self._add_user_to_room(room_id, RoomVersions.V1, local_user_3)
|
||||
|
||||
# Create a few "remote" users and join them to the room
|
||||
remote_user_1 = "@user_aaaaa:remote_server"
|
||||
remote_user_2 = "@user_yyyyy:remote_server"
|
||||
remote_user_3 = "@user_ccccc:remote_server"
|
||||
self._add_user_to_room(room_id, RoomVersions.V1, remote_user_1)
|
||||
self._add_user_to_room(room_id, RoomVersions.V1, remote_user_2)
|
||||
self._add_user_to_room(room_id, RoomVersions.V1, remote_user_3)
|
||||
|
||||
local_users = [local_user_1, local_user_2, local_user_3]
|
||||
remote_users = [remote_user_1, remote_user_2, remote_user_3]
|
||||
|
||||
# The local searching user searches for the term "user", which other users have
|
||||
# in their user id
|
||||
results = self.get_success(
|
||||
self.handler.search_users(searching_user, "user", 20)
|
||||
)["results"]
|
||||
received_user_ids = [result["user_id"] for result in results]
|
||||
|
||||
for user in local_users:
|
||||
self.assertIn(
|
||||
user, received_user_ids, f"Local user {user} not found in results"
|
||||
)
|
||||
|
||||
for user in remote_users:
|
||||
self.assertNotIn(
|
||||
user, received_user_ids, f"Remote user {user} should not be in results"
|
||||
)
|
||||
|
||||
def _add_user_to_room(
|
||||
self,
|
||||
room_id: str,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user