mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	Support email changes for !avatar syntax.
Significantly modified by tabbott to avoid calling get_user_profile_by_email in bugdown, and have 100% test coverage of the views code. Fixes #2041.
This commit is contained in:
		@@ -37,7 +37,7 @@ from zerver.lib.timeout import timeout, TimeoutExpired
 | 
				
			|||||||
from zerver.lib.cache import (
 | 
					from zerver.lib.cache import (
 | 
				
			||||||
    cache_with_key, cache_get_many, cache_set_many, NotFoundInCache)
 | 
					    cache_with_key, cache_get_many, cache_set_many, NotFoundInCache)
 | 
				
			||||||
from zerver.lib.url_preview import preview as link_preview
 | 
					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.alert_words as alert_words
 | 
				
			||||||
import zerver.lib.mention as mention
 | 
					import zerver.lib.mention as mention
 | 
				
			||||||
from zerver.lib.str_utils import force_text, force_str
 | 
					from zerver.lib.str_utils import force_text, force_str
 | 
				
			||||||
@@ -635,10 +635,18 @@ class Avatar(markdown.inlinepatterns.Pattern):
 | 
				
			|||||||
        # type: (Match[Text]) -> Optional[Element]
 | 
					        # type: (Match[Text]) -> Optional[Element]
 | 
				
			||||||
        img = markdown.util.etree.Element('img')
 | 
					        img = markdown.util.etree.Element('img')
 | 
				
			||||||
        email_address = match.group('email')
 | 
					        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('class', 'message_body_gravatar')
 | 
				
			||||||
        img.set('src', '/avatar/%s?s=30' % (email_address,))
 | 
					        img.set('src', '/avatar/{0}?s=30'.format(profile_id or email))
 | 
				
			||||||
        img.set('title', email_address)
 | 
					        img.set('title', email)
 | 
				
			||||||
        img.set('alt', email_address)
 | 
					        img.set('alt', email)
 | 
				
			||||||
        return img
 | 
					        return img
 | 
				
			||||||
 | 
					
 | 
				
			||||||
emoji_tree = os.path.join(settings.STATIC_ROOT, "generated", "emoji", "images", "emoji")
 | 
					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,
 | 
					        db_data = {'possible_words': possible_words,
 | 
				
			||||||
                   'full_names': dict((user['full_name'].lower(), user) for user in realm_users),
 | 
					                   '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),
 | 
					                   '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(),
 | 
					                   'emoji': message_realm.get_emoji(),
 | 
				
			||||||
                   'sent_by_bot': sent_by_bot,
 | 
					                   'sent_by_bot': sent_by_bot,
 | 
				
			||||||
                   'stream_names': dict((stream['name'], stream) for stream in realm_streams)}
 | 
					                   'stream_names': dict((stream['name'], stream) for stream in realm_streams)}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -896,3 +896,30 @@ class BugdownErrorTests(ZulipTestCase):
 | 
				
			|||||||
            # handle i18n properly here on some systems.
 | 
					            # handle i18n properly here on some systems.
 | 
				
			||||||
            with self.assertRaises(JsonableError):
 | 
					            with self.assertRaises(JsonableError):
 | 
				
			||||||
                self.send_message("othello@zulip.com", "Denmark", Recipient.STREAM, message)
 | 
					                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,
 | 
				
			||||||
 | 
					            '<p><img alt="{email}" class="message_body_gravatar" src="/avatar/{id}?s=30" title="{email}"></p>'.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,
 | 
				
			||||||
 | 
					            '<p><img alt="{0}" class="message_body_gravatar" src="/avatar/{0}?s=30" title="{0}"></p>'.format(email))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -381,6 +381,10 @@ class AvatarTest(UploadSerializeMixin, ZulipTestCase):
 | 
				
			|||||||
        redirect_url = response['Location']
 | 
					        redirect_url = response['Location']
 | 
				
			||||||
        self.assertTrue(redirect_url.endswith(avatar_url(cordelia) + '&foo=bar'))
 | 
					        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):
 | 
					    def test_non_valid_user_avatar(self):
 | 
				
			||||||
        # type: () -> None
 | 
					        # type: () -> None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.users import check_change_full_name, check_full_name
 | 
				
			||||||
from zerver.lib.utils import generate_random_token
 | 
					from zerver.lib.utils import generate_random_token
 | 
				
			||||||
from zerver.models import UserProfile, Stream, Realm, Message, get_user_profile_by_email, \
 | 
					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
 | 
					from zproject.jinja2 import render_to_response
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -112,12 +112,26 @@ def update_user_backend(request, user_profile, email,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return json_success()
 | 
					    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
 | 
					    # type: (HttpRequest, str) -> HttpResponse
 | 
				
			||||||
 | 
					    """Accepts an email address or user ID and returns the avatar"""
 | 
				
			||||||
    try:
 | 
					    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)
 | 
					        url = avatar_url(user_profile)
 | 
				
			||||||
    except UserProfile.DoesNotExist:
 | 
					    except UserProfile.DoesNotExist:
 | 
				
			||||||
 | 
					        # If there is no such user, treat it as a new gravatar
 | 
				
			||||||
 | 
					        email = email_or_id
 | 
				
			||||||
        avatar_source = 'G'
 | 
					        avatar_source = 'G'
 | 
				
			||||||
        avatar_version = 1
 | 
					        avatar_version = 1
 | 
				
			||||||
        url = get_avatar_url(avatar_source, email, avatar_version)
 | 
					        url = get_avatar_url(avatar_source, email, avatar_version)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -93,7 +93,7 @@ i18n_urls = [
 | 
				
			|||||||
        {'template_name': 'zerver/reset_done.html'}),
 | 
					        {'template_name': 'zerver/reset_done.html'}),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Avatar
 | 
					    # Avatar
 | 
				
			||||||
    url(r'^avatar/(?P<email>[\S]+)?', zerver.views.users.avatar, name='zerver.views.users.avatar'),
 | 
					    url(r'^avatar/(?P<email_or_id>[\S]+)?', zerver.views.users.avatar, name='zerver.views.users.avatar'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Registration views, require a confirmation ID.
 | 
					    # Registration views, require a confirmation ID.
 | 
				
			||||||
    url(r'^accounts/home/', zerver.views.registration.accounts_home,
 | 
					    url(r'^accounts/home/', zerver.views.registration.accounts_home,
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user