summary refs log tree commit diff
path: root/synapse/storage
diff options
context:
space:
mode:
authorAndrew Morgan <1342360+anoadragon453@users.noreply.github.com>2020-06-19 16:17:13 +0100
committerGitHub <noreply@github.com>2020-06-19 16:17:13 +0100
commit53949a908fc785ab6c27b40343040df2462cd309 (patch)
tree23feb3417a2bc47d0d9c1ab3be13c383ea07a261 /synapse/storage
parentPerformance improvements to marking expired users as inactive (#47) (diff)
downloadsynapse-53949a908fc785ab6c27b40343040df2462cd309.tar.xz
Add a bulk user info endpoint and deprecate the old one (#46)
The current `/user/<user_id>/info` API was useful in that it could be used by any user to lookup whether another user was deactivate or expired. However, it was impractical as it only allowed for a single lookup at once. Clients trying to use this API were met with speed issues as they tried to query this information for all users in a room.

This PR adds an equivalent CS and Federation API that takes a list of user IDs, and returning a mapping from user ID to info dictionary.

Note that the federation in this PR was a bit trickier than in the original #12 as we can no longer use a federation query, as those don't allow for JSON bodies - which we require to pass a list of user IDs. Instead we do the whole thing of adding a method to transport/client and transport/server.

This PR also adds unittests. The earlier PR used Sytest, presumably for testing across federation, but as this is Synapse-specific that felt a little gross. Unit tests for the deprecated endpoint have not been added.
Diffstat (limited to 'synapse/storage')
-rw-r--r--synapse/storage/data_stores/main/registration.py50
1 files changed, 50 insertions, 0 deletions
diff --git a/synapse/storage/data_stores/main/registration.py b/synapse/storage/data_stores/main/registration.py

index b07c44d87a..1f1a7b4e36 100644 --- a/synapse/storage/data_stores/main/registration.py +++ b/synapse/storage/data_stores/main/registration.py
@@ -17,6 +17,7 @@ import logging import re +from typing import List from six import iterkeys @@ -304,6 +305,55 @@ class RegistrationWorkerStore(SQLBaseStore): desc="delete_account_validity_for_user", ) + @defer.inlineCallbacks + def get_info_for_users( + self, user_ids: List[str], + ): + """Return the user info for a given set of users + + Args: + user_ids: A list of users to return information about + + Returns: + Deferred[Dict[str, bool]]: A dictionary mapping each user ID to + a dict with the following keys: + * expired - whether this is an expired user + * deactivated - whether this is a deactivated user + """ + # Get information of all our local users + def _get_info_for_users_txn(txn): + rows = [] + + for user_id in user_ids: + sql = """ + SELECT u.name, u.deactivated, av.expiration_ts_ms + FROM users as u + LEFT JOIN account_validity as av + ON av.user_id = u.name + WHERE u.name = ? + """ + + txn.execute(sql, (user_id,)) + row = txn.fetchone() + if row: + rows.append(row) + + return rows + + info_rows = yield self.db.runInteraction( + "get_info_for_users", _get_info_for_users_txn + ) + + return { + user_id: { + "expired": ( + expiration is not None and self.clock.time_msec() >= expiration + ), + "deactivated": deactivated == 1, + } + for user_id, deactivated, expiration in info_rows + } + async def is_server_admin(self, user): """Determines if a user is an admin of this homeserver.