diff --git a/zerver/lib/bugdown/__init__.py b/zerver/lib/bugdown/__init__.py index 896d1a7b41..ac112865d9 100644 --- a/zerver/lib/bugdown/__init__.py +++ b/zerver/lib/bugdown/__init__.py @@ -37,7 +37,7 @@ from zerver.lib.timeout import timeout, TimeoutExpired from zerver.lib.cache import ( cache_with_key, cache_get_many, cache_set_many, NotFoundInCache) from zerver.lib.url_preview import preview as link_preview -from zerver.models import Message, Realm +from zerver.models import Message, Realm, UserProfile, get_user_profile_by_email import zerver.lib.alert_words as alert_words import zerver.lib.mention as mention from zerver.lib.str_utils import force_text, force_str @@ -635,10 +635,18 @@ class Avatar(markdown.inlinepatterns.Pattern): # type: (Match[Text]) -> Optional[Element] img = markdown.util.etree.Element('img') email_address = match.group('email') + email = email_address.strip().lower() + profile_id = None + + if db_data is not None: + user_dict = db_data['by_email'].get(email) + if user_dict is not None: + profile_id = user_dict['id'] + img.set('class', 'message_body_gravatar') - img.set('src', '/avatar/%s?s=30' % (email_address,)) - img.set('title', email_address) - img.set('alt', email_address) + img.set('src', '/avatar/{0}?s=30'.format(profile_id or email)) + img.set('title', email) + img.set('alt', email) return img emoji_tree = os.path.join(settings.STATIC_ROOT, "generated", "emoji", "images", "emoji") @@ -1350,6 +1358,7 @@ def do_convert(content, message=None, message_realm=None, possible_words=None, s db_data = {'possible_words': possible_words, 'full_names': dict((user['full_name'].lower(), user) for user in realm_users), 'short_names': dict((user['short_name'].lower(), user) for user in realm_users), + 'by_email': dict((user['email'].lower(), user) for user in realm_users), 'emoji': message_realm.get_emoji(), 'sent_by_bot': sent_by_bot, 'stream_names': dict((stream['name'], stream) for stream in realm_streams)} diff --git a/zerver/tests/test_bugdown.py b/zerver/tests/test_bugdown.py index 77887ac306..9332b0da22 100644 --- a/zerver/tests/test_bugdown.py +++ b/zerver/tests/test_bugdown.py @@ -896,3 +896,30 @@ class BugdownErrorTests(ZulipTestCase): # handle i18n properly here on some systems. with self.assertRaises(JsonableError): self.send_message("othello@zulip.com", "Denmark", Recipient.STREAM, message) + + +class BugdownAvatarTestCase(ZulipTestCase): + def test_avatar_with_id(self): + # type: () -> None + sender_user_profile = get_user_profile_by_email("othello@zulip.com") + message = Message(sender=sender_user_profile, sending_client=get_client("test")) + + user_profile = get_user_profile_by_email("hamlet@zulip.com") + msg = '!avatar({0})'.format(user_profile.email) + converted = bugdown.convert(msg, message=message) + values = {'email': user_profile.email, 'id': user_profile.id} + self.assertEqual( + converted, + '

{email}

'.format(**values)) + + def test_avatar_of_unregistered_user(self): + # type: () -> None + sender_user_profile = get_user_profile_by_email("othello@zulip.com") + message = Message(sender=sender_user_profile, sending_client=get_client("test")) + + email = 'fakeuser@example.com' + msg = '!avatar({0})'.format(email) + converted = bugdown.convert(msg, message=message) + self.assertEqual( + converted, + '

{0}

'.format(email)) diff --git a/zerver/tests/test_upload.py b/zerver/tests/test_upload.py index eab723f4e0..4142aa1a07 100644 --- a/zerver/tests/test_upload.py +++ b/zerver/tests/test_upload.py @@ -381,6 +381,10 @@ class AvatarTest(UploadSerializeMixin, ZulipTestCase): redirect_url = response['Location'] self.assertTrue(redirect_url.endswith(avatar_url(cordelia) + '&foo=bar')) + response = self.client_get("/avatar/%s?foo=bar" % (cordelia.id)) + redirect_url = response['Location'] + self.assertTrue(redirect_url.endswith(avatar_url(cordelia) + '&foo=bar')) + def test_non_valid_user_avatar(self): # type: () -> None diff --git a/zerver/views/users.py b/zerver/views/users.py index 33b46a63c7..7af1e5858f 100644 --- a/zerver/views/users.py +++ b/zerver/views/users.py @@ -26,7 +26,7 @@ from zerver.lib.validator import check_bool, check_string from zerver.lib.users import check_change_full_name, check_full_name from zerver.lib.utils import generate_random_token from zerver.models import UserProfile, Stream, Realm, Message, get_user_profile_by_email, \ - email_allowed_for_realm + email_allowed_for_realm, get_user_profile_by_id from zproject.jinja2 import render_to_response @@ -112,12 +112,26 @@ def update_user_backend(request, user_profile, email, return json_success() -def avatar(request, email): +# TODO: Since eventually we want to support using the same email with +# different organizations, we'll eventually want this to be a +# logged-in endpoint so that we can access the realm_id. +def avatar(request, email_or_id): # type: (HttpRequest, str) -> HttpResponse + """Accepts an email address or user ID and returns the avatar""" try: - user_profile = get_user_profile_by_email(email) + int(email_or_id) + except ValueError: + get_user_func = get_user_profile_by_email + else: + get_user_func = get_user_profile_by_id + + try: + # If there is a valid user account passed in, use its avatar + user_profile = get_user_func(email_or_id) url = avatar_url(user_profile) except UserProfile.DoesNotExist: + # If there is no such user, treat it as a new gravatar + email = email_or_id avatar_source = 'G' avatar_version = 1 url = get_avatar_url(avatar_source, email, avatar_version) diff --git a/zproject/urls.py b/zproject/urls.py index 780739731f..d9c750124f 100644 --- a/zproject/urls.py +++ b/zproject/urls.py @@ -93,7 +93,7 @@ i18n_urls = [ {'template_name': 'zerver/reset_done.html'}), # Avatar - url(r'^avatar/(?P[\S]+)?', zerver.views.users.avatar, name='zerver.views.users.avatar'), + url(r'^avatar/(?P[\S]+)?', zerver.views.users.avatar, name='zerver.views.users.avatar'), # Registration views, require a confirmation ID. url(r'^accounts/home/', zerver.views.registration.accounts_home,