Add client_gratavar support to GET /messages.

Clients fetching messages can now specify that they are able
to compute their avatar, and if they set client_gratavar to
True in the request (w/our normal encoding scheme), then the
backend will not compute it, and the payload will be smaller.

The fix starts with get_messages_backend.  The flag gets
passed down through these functions:

    * MessageDict.post_process_dicts.
    * MessageDict.set_sender_avatar.

We also fix up the callers for post_process_dicts to explicitly
pass in the client_gravatar path, but for now they all just hard
code the value to False.
This commit is contained in:
Steve Howell 2017-10-20 07:52:04 -07:00 committed by Tim Abbott
parent 42d6defd40
commit 0e106a2488
4 changed files with 41 additions and 14 deletions

View File

@ -78,7 +78,17 @@ def message_to_dict(message, apply_markdown):
# type: (Message, bool) -> Dict[str, Any]
json = message_to_dict_json(message, apply_markdown)
obj = extract_message_dict(json)
MessageDict.post_process_dicts([obj])
'''
In this codepath we do net yet optimize for clients
that can compute their own gravatar URLs.
'''
client_gravatar = False
MessageDict.post_process_dicts(
[obj],
client_gravatar=client_gravatar,
)
return obj
@cache_with_key(to_dict_cache_key, timeout=3600*24)
@ -88,13 +98,13 @@ def message_to_dict_json(message, apply_markdown):
class MessageDict(object):
@staticmethod
def post_process_dicts(objs):
# type: (List[Dict[str, Any]]) -> None
def post_process_dicts(objs, client_gravatar):
# type: (List[Dict[str, Any]], bool) -> None
MessageDict.bulk_hydrate_sender_info(objs)
for obj in objs:
MessageDict.hydrate_recipient_info(obj)
MessageDict.set_sender_avatar(obj)
MessageDict.set_sender_avatar(obj, client_gravatar)
del obj['sender_realm_id']
del obj['sender_avatar_source']
@ -366,17 +376,14 @@ class MessageDict(object):
obj['stream_id'] = recipient_type_id
@staticmethod
def set_sender_avatar(obj):
# type: (Dict[str, Any]) -> None
def set_sender_avatar(obj, client_gravatar):
# type: (Dict[str, Any], bool) -> None
sender_id = obj['sender_id']
sender_realm_id = obj['sender_realm_id']
sender_email = obj['sender_email']
sender_avatar_source = obj['sender_avatar_source']
sender_avatar_version = obj['sender_avatar_version']
# TODO: Make client_gravatar configurable.
client_gravatar = False
obj['avatar_url'] = get_avatar_field(
user_id=sender_id,
realm_id=sender_realm_id,

View File

@ -576,7 +576,7 @@ class StreamMessagesTest(ZulipTestCase):
message = most_recent_message(user_profile)
row = MessageDict.get_raw_db_rows([message.id])[0]
dct = MessageDict.build_dict_from_raw_db_row(row, apply_markdown=True)
MessageDict.post_process_dicts([dct])
MessageDict.post_process_dicts([dct], client_gravatar=False)
self.assertEqual(dct['display_recipient'], 'Denmark')
stream = get_stream('Denmark', user_profile.realm)
@ -699,7 +699,7 @@ class MessageDictTest(ZulipTestCase):
MessageDict.build_dict_from_raw_db_row(row, False)
for row in rows
]
MessageDict.post_process_dicts(objs)
MessageDict.post_process_dicts(objs, client_gravatar=False)
delay = time.time() - t
# Make sure we don't take longer than 1.5ms per message to
@ -1268,7 +1268,7 @@ class EditMessageTest(ZulipTestCase):
msg = Message.objects.get(id=msg_id)
cached = message_to_dict(msg, False)
uncached = MessageDict.to_dict_uncached_helper(msg, False)
MessageDict.post_process_dicts([uncached])
MessageDict.post_process_dicts([uncached], client_gravatar=False)
self.assertEqual(cached, uncached)
if subject:
self.assertEqual(msg.topic_name(), subject)

View File

@ -518,6 +518,24 @@ class GetOldMessagesTest(ZulipTestCase):
self.get_and_check_messages(dict(narrow=ujson.dumps([dict(operator='pm-with', operand=self.example_email("othello"))])))
def test_client_avatar(self):
# type: () -> None
"""
The client_gravatar flag determines whether we send avatar_url.
"""
hamlet = self.example_user('hamlet')
self.login(hamlet.email)
self.send_message(hamlet.email, self.example_email("iago"), Recipient.PERSONAL)
result = self.get_and_check_messages({})
message = result['messages'][0]
self.assertIn('gravatar.com', message['avatar_url'])
result = self.get_and_check_messages(dict(client_gravatar=ujson.dumps(True)))
message = result['messages'][0]
self.assertEqual(message['avatar_url'], None)
def test_get_messages_with_narrow_pm_with(self):
# type: () -> None
"""

View File

@ -563,9 +563,11 @@ def get_messages_backend(request, user_profile,
num_after = REQ(converter=to_non_negative_int),
narrow = REQ('narrow', converter=narrow_parameter, default=None),
use_first_unread_anchor = REQ(default=False, converter=ujson.loads),
client_gravatar=REQ(default=False,
converter=ujson.loads),
apply_markdown=REQ(default=True,
converter=ujson.loads)):
# type: (HttpRequest, UserProfile, int, int, int, Optional[List[Dict[str, Any]]], bool, bool) -> HttpResponse
# type: (HttpRequest, UserProfile, int, int, int, Optional[List[Dict[str, Any]]], bool, bool, bool) -> HttpResponse
include_history = ok_to_include_history(narrow, user_profile.realm)
if include_history and not use_first_unread_anchor:
@ -760,7 +762,7 @@ def get_messages_backend(request, user_profile,
del msg_dict["edit_history"]
message_list.append(msg_dict)
MessageDict.post_process_dicts(message_list)
MessageDict.post_process_dicts(message_list, client_gravatar)
statsd.incr('loaded_old_messages', len(message_list))
ret = {'messages': message_list,