-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
add Module API callback for user directory search #12318
base: develop
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,7 +13,7 @@ | |
# limitations under the License. | ||
|
||
import logging | ||
from typing import TYPE_CHECKING, Any, Dict, List, Optional | ||
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, List, Optional | ||
|
||
import synapse.metrics | ||
from synapse.api.constants import EventTypes, HistoryVisibility, JoinRules, Membership | ||
|
@@ -28,6 +28,9 @@ | |
|
||
logger = logging.getLogger(__name__) | ||
|
||
# Types for callbacks to be registered via the module api | ||
ON_SEARH_USERS_CALLBACK = Callable[[str, str, int], Awaitable[Optional[SearchResult]]] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would also like this callback's name to better reflect what it does. In this case, maybe something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough, I didn't consider the sequential meaning There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
|
||
class UserDirectoryHandler(StateDeltasHandler): | ||
"""Handles queries and updates for the user_directory. | ||
|
@@ -76,6 +79,14 @@ def __init__(self, hs: "HomeServer"): | |
# we start populating the user directory | ||
self.clock.call_later(0, self.notify_new_event) | ||
|
||
self._on_search_users_callbacks: List[ON_SEARH_USERS_CALLBACK] = [] | ||
|
||
def register_user_directory_callbacks( | ||
self, on_search_users: Optional[ON_SEARH_USERS_CALLBACK] = None | ||
) -> None: | ||
if on_search_users is not None: | ||
self._on_search_users_callbacks.append(on_search_users) | ||
|
||
async def search_users( | ||
self, user_id: str, search_term: str, limit: int | ||
) -> SearchResult: | ||
|
@@ -97,6 +108,20 @@ async def search_users( | |
""" | ||
results = await self.store.search_user_dir(user_id, search_term, limit) | ||
|
||
merged_results = results["results"] | ||
existing_user_ids = [user["user_id"] for user in merged_results] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. merging the external user directory with synapse's works so that: if user_id match -> user match. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel like we'd want the external backend to have the last word here, so I think we can just call |
||
for callback in self._on_search_users_callbacks: | ||
external_users = await callback(user_id, search_term, limit) | ||
if external_users is not None: | ||
merged_results += [ | ||
Samonitari marked this conversation as resolved.
Show resolved
Hide resolved
|
||
user | ||
for user in external_users["results"] | ||
if user["user_id"] not in existing_user_ids | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to see some error handling around this so that a faulty module doesn't completely disable user search. See this snippet for inspiration. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough, correcting |
||
|
||
results["results"] = merged_results | ||
results["limited"] = len(merged_results) > limit | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it makes much sense to update There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did only really understood the logic behind OTOH, the correct merging would be maybe:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to clarify, this would mean that if the database query yielded a limited result set we would only show results in the external backend if their user ID appears in the result set from the database. That's assuming we change the merge logic as suggested in #12318 (comment). Otherwise it means we don't show results (and presumably don't call the callback at all) unless the database doesn't manage to provide a This I guess would make sense even though it's not a super obvious behaviour at first. Though it sounds to me like it would fill a rather niche case; in my experience it would be more logical to expect the other way around, with the custom external backend being the source of truth and falling back to Synapse's generic search to fill in the blanks. I think doing it this way would be more helpful. |
||
|
||
# Remove any spammy users from the results. | ||
non_spammy_users = [] | ||
for user in results["results"]: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.