diff --git a/zerver/lib/users.py b/zerver/lib/users.py index 2e582c2581..2c876cbe74 100644 --- a/zerver/lib/users.py +++ b/zerver/lib/users.py @@ -395,15 +395,29 @@ def get_custom_profile_field_values(custom_profile_field_values: return profiles_by_user_id def get_raw_user_data(realm: Realm, acting_user: UserProfile, client_gravatar: bool, + target_user: Optional[UserProfile]=None, include_custom_profile_fields: bool=True) -> Dict[int, Dict[str, str]]: - user_dicts = get_realm_user_dicts(realm.id) + """Fetches data about the target user(s) appropriate for sending to + acting_user via the standard format for the Zulip API. If + target_user is None, we fetch all users in the realm. + """ profiles_by_user_id = None custom_profile_field_data = None + # target_user is an optional parameter which is passed when user data of a specific user + # is required. It is 'None' otherwise. + if target_user is not None: + user_dicts = [user_profile_to_user_row(target_user)] + else: + user_dicts = get_realm_user_dicts(realm.id) if include_custom_profile_fields: base_query = CustomProfileFieldValue.objects.select_related("field") # TODO: Consider optimizing this query away with caching. custom_profile_field_values = base_query.filter(user_profile__realm_id=realm.id) + if target_user is not None: + custom_profile_field_values = base_query.filter(user_profile=target_user) + else: + custom_profile_field_values = base_query.filter(user_profile__realm_id=realm.id) profiles_by_user_id = get_custom_profile_field_values(custom_profile_field_values) result = {} diff --git a/zerver/tests/test_users.py b/zerver/tests/test_users.py index b369642409..1ecacf9eb0 100644 --- a/zerver/tests/test_users.py +++ b/zerver/tests/test_users.py @@ -1336,6 +1336,22 @@ class GetProfileTest(ZulipTestCase): self.assertFalse(result['is_bot']) self.assertTrue(result['is_admin']) + # Tests the GET ../users/{id} api endpoint. + user = self.example_user('hamlet') + result = ujson.loads(self.client_get('/json/users/{}'.format(user.id)).content) + self.assertEqual(result['members'][0]['email'], user.email) + self.assertEqual(result['members'][0]['full_name'], user.full_name) + self.assertIn("user_id", result['members'][0]) + self.assertNotIn("profile_data", result['members'][0]) + self.assertFalse(result['members'][0]['is_bot']) + self.assertFalse(result['members'][0]['is_admin']) + + result = ujson.loads(self.client_get('/json/users/{}?include_custom_profile_fields=true'.format(user.id)).content) + + self.assertIn('profile_data', result['members'][0]) + result = self.client_get('/json/users/{}?'.format(30)) + self.assert_json_error(result, "No such user") + def test_api_get_empty_profile(self) -> None: """ Ensure GET /users/me returns a max message id and returns successfully diff --git a/zerver/views/users.py b/zerver/views/users.py index 087e99612f..16015a60d0 100644 --- a/zerver/views/users.py +++ b/zerver/views/users.py @@ -395,7 +395,7 @@ def get_bots_backend(request: HttpRequest, user_profile: UserProfile) -> HttpRes return json_success({'bots': list(map(bot_info, bot_profiles))}) @has_request_variables -def get_members_backend(request: HttpRequest, user_profile: UserProfile, +def get_members_backend(request: HttpRequest, user_profile: UserProfile, user_id: Optional[int]=None, include_custom_profile_fields: bool=REQ(validator=check_bool, default=False), client_gravatar: bool=REQ(validator=check_bool, default=False) @@ -411,7 +411,13 @@ def get_members_backend(request: HttpRequest, user_profile: UserProfile, # If email addresses are only available to administrators, # clients cannot compute gravatars, so we force-set it to false. client_gravatar = False + target_user = None + if user_id is not None: + target_user = access_user_by_id(user_profile, user_id, allow_deactivated=True, + read_only=True) + members = get_raw_user_data(realm, user_profile, client_gravatar=client_gravatar, + target_user=target_user, include_custom_profile_fields=include_custom_profile_fields) return json_success({'members': members.values()}) diff --git a/zproject/urls.py b/zproject/urls.py index 498d3de4e2..c7ca542ae9 100644 --- a/zproject/urls.py +++ b/zproject/urls.py @@ -146,7 +146,8 @@ v1_api_and_json_patterns = [ url(r'^users/(?!me/)(?P[^/]*)/presence$', rest_dispatch, {'GET': 'zerver.views.presence.get_presence_backend'}), url(r'^users/(?P[0-9]+)$', rest_dispatch, - {'PATCH': 'zerver.views.users.update_user_backend', + {'GET': 'zerver.views.users.get_members_backend', + 'PATCH': 'zerver.views.users.update_user_backend', 'DELETE': 'zerver.views.users.deactivate_user_backend'}), url(r'^bots$', rest_dispatch, {'GET': 'zerver.views.users.get_bots_backend',