def avatar(request: HttpRequest, email_or_id: str, medium: bool=False) -> HttpResponse: """Accepts an email address or user ID and returns the avatar""" is_email = False try: int(email_or_id) except ValueError: is_email = True try: if is_email: realm = request.user.realm user_profile = get_user_including_cross_realm(email_or_id, realm) else: user_profile = get_user_profile_by_id(email_or_id) # If there is a valid user account passed in, use its avatar url = avatar_url(user_profile, medium=medium) except UserProfile.DoesNotExist: # If there is no such user, treat it as a new gravatar email = email_or_id avatar_version = 1 url = get_gravatar_url(email, avatar_version, medium) # We can rely on the url already having query parameters. Because # our templates depend on being able to use the ampersand to # add query parameters to our url, get_avatar_url does '?x=x' # hacks to prevent us from having to jump through decode/encode hoops. assert '?' in url url += '&' + request.META['QUERY_STRING'] return redirect(url)
def archive(request: HttpRequest, stream_id: int, topic_name: str) -> HttpResponse: def get_response(rendered_message_list: List[str], is_web_public: bool, stream_name: str) -> HttpResponse: return render( request, 'zerver/archive/index.html', context={ 'is_web_public': is_web_public, 'message_list': rendered_message_list, 'stream': stream_name, 'topic': topic_name, } ) try: stream = get_stream_by_id(stream_id) except JsonableError: return get_response([], False, '') if not stream.is_web_public: return get_response([], False, '') all_messages = list(Message.objects.select_related( 'sender').filter(recipient__type_id=stream_id, subject=topic_name).order_by('pub_date')) if not all_messages: return get_response([], True, stream.name) rendered_message_list = [] prev_sender = None for msg in all_messages: include_sender = False status_message = Message.is_status_message(msg.content, msg.rendered_content) if not prev_sender or prev_sender != msg.sender or status_message: if status_message: prev_sender = None else: prev_sender = msg.sender include_sender = True if status_message: status_message = msg.rendered_content[4+3: -4] context = { 'sender_full_name': msg.sender.full_name, 'timestampstr': datetime_to_timestamp(msg.last_edit_time if msg.last_edit_time else msg.pub_date), 'message_content': msg.rendered_content, 'avatar_url': get_gravatar_url(msg.sender.email, 1), 'include_sender': include_sender, 'status_message': status_message, } rendered_msg = loader.render_to_string('zerver/archive/single_message.html', context) rendered_message_list.append(rendered_msg) return get_response(rendered_message_list, True, stream.name)
def archive(request: HttpRequest, stream_id: int, topic_name: str) -> HttpResponse: def get_response(rendered_message_list: List[str], is_web_public: bool, stream_name: str) -> HttpResponse: return render( request, "zerver/archive/index.html", context={ "is_web_public": is_web_public, "message_list": rendered_message_list, "stream": stream_name, "topic": topic_name, }, ) try: realm = get_request_notes(request).realm assert realm is not None stream = access_web_public_stream(stream_id, realm) except JsonableError: return get_response([], False, "") all_messages = list( messages_for_topic( stream_recipient_id=stream.recipient_id, topic_name=topic_name, ).select_related("sender").order_by("date_sent"), ) if not all_messages: return get_response([], True, stream.name) rendered_message_list = [] prev_sender: Optional[UserProfile] = None for msg in all_messages: include_sender = False status_message = Message.is_status_message(msg.content, msg.rendered_content) if not prev_sender or prev_sender != msg.sender or status_message: if status_message: prev_sender = None else: prev_sender = msg.sender include_sender = True if status_message: status_message = msg.rendered_content[4 + 3:-4] context = { "sender_full_name": msg.sender.full_name, "timestampstr": datetime_to_timestamp( msg.last_edit_time if msg.last_edit_time else msg.date_sent), "message_content": msg.rendered_content, "avatar_url": get_gravatar_url(msg.sender.delivery_email, 1), "include_sender": include_sender, "status_message": status_message, } rendered_msg = loader.render_to_string( "zerver/archive/single_message.html", context) rendered_message_list.append(rendered_msg) return get_response(rendered_message_list, True, stream.name)
def archive(request: HttpRequest, stream_id: int, topic_name: str) -> HttpResponse: def get_response(rendered_message_list: List[str], is_web_public: bool, stream_name: str) -> HttpResponse: return render(request, 'zerver/archive/index.html', context={ 'is_web_public': is_web_public, 'message_list': rendered_message_list, 'stream': stream_name, 'topic': topic_name, }) try: stream = get_stream_by_id(stream_id) except JsonableError: return get_response([], False, '') if not stream.is_web_public: return get_response([], False, '') all_messages = list( messages_for_topic( stream_id=stream_id, topic_name=topic_name, ).select_related('sender').order_by('date_sent')) if not all_messages: return get_response([], True, stream.name) rendered_message_list = [] prev_sender = None # type: Optional[UserProfile] for msg in all_messages: include_sender = False status_message = Message.is_status_message(msg.content, msg.rendered_content) if not prev_sender or prev_sender != msg.sender or status_message: if status_message: prev_sender = None else: prev_sender = msg.sender include_sender = True if status_message: status_message = msg.rendered_content[4 + 3:-4] context = { 'sender_full_name': msg.sender.full_name, 'timestampstr': datetime_to_timestamp( msg.last_edit_time if msg.last_edit_time else msg.date_sent), 'message_content': msg.rendered_content, 'avatar_url': get_gravatar_url(msg.sender.email, 1), 'include_sender': include_sender, 'status_message': status_message, } rendered_msg = loader.render_to_string( 'zerver/archive/single_message.html', context) rendered_message_list.append(rendered_msg) return get_response(rendered_message_list, True, stream.name)
def avatar( request: HttpRequest, maybe_user_profile: Union[UserProfile, AnonymousUser], email_or_id: str, medium: bool = False, ) -> HttpResponse: """Accepts an email address or user ID and returns the avatar""" is_email = False try: int(email_or_id) except ValueError: is_email = True if not maybe_user_profile.is_authenticated: # Allow anonymous access to avatars only if spectators are # enabled in the organization. realm = get_valid_realm_from_request(request) if not realm.allow_web_public_streams_access(): raise MissingAuthenticationError() # We only allow the ID format for accessing a user's avatar # for spectators. This is mainly for defense in depth, since # email_address_visibility should mean spectators only # interact with fake email addresses anyway. if is_email: raise MissingAuthenticationError() if settings.RATE_LIMITING: try: unique_avatar_key = f"{realm.id}/{email_or_id}/{medium}" rate_limit_spectator_attachment_access_by_file( unique_avatar_key) except RateLimited: return json_response_from_error( RateLimited( _("Too many attempts, please try after some time."))) else: realm = maybe_user_profile.realm try: if is_email: avatar_user_profile = get_user_including_cross_realm( email_or_id, realm) else: avatar_user_profile = get_user_by_id_in_realm_including_cross_realm( int(email_or_id), realm) # If there is a valid user account passed in, use its avatar url = avatar_url(avatar_user_profile, medium=medium) except UserProfile.DoesNotExist: # If there is no such user, treat it as a new gravatar email = email_or_id avatar_version = 1 url = get_gravatar_url(email, avatar_version, medium) # We can rely on the URL already having query parameters. Because # our templates depend on being able to use the ampersand to # add query parameters to our url, get_avatar_url does '?x=x' # hacks to prevent us from having to jump through decode/encode hoops. assert url is not None url = append_url_query_string(url, request.META["QUERY_STRING"]) return redirect(url)
def test_make_request(self) -> None: othello = self.example_user("othello") stream = get_stream("Denmark", othello.realm) message_id = self.send_stream_message( othello, stream.name, content="@**test**", ) message = Message.objects.get(id=message_id) gravatar_url = get_gravatar_url( othello.delivery_email, othello.avatar_version, ) expected_message_data = { "avatar_url": gravatar_url, "client": "test suite", "content": "@**test**", "content_type": "text/x-markdown", "display_recipient": "Denmark", "id": message.id, "is_me_message": False, "reactions": [], "recipient_id": message.recipient_id, "rendered_content": "<p>@<strong>test</strong></p>", "sender_email": othello.email, "sender_full_name": "Othello, the Moor of Venice", "sender_id": othello.id, "sender_realm_str": "zulip", "stream_id": stream.id, TOPIC_NAME: "test", "submessages": [], "timestamp": datetime_to_timestamp(message.date_sent), "topic_links": [], "type": "stream", } wide_message_dict = MessageDict.wide_dict(message) event = { "command": "@**test**", "message": wide_message_dict, "trigger": "mention", } test_url = "https://example.com/example" with mock.patch.object(self.handler, "session") as session: self.handler.make_request( test_url, event, ) session.post.assert_called_once() self.assertEqual(session.post.call_args[0], (test_url,)) request_data = session.post.call_args[1]["json"] validate_against_openapi_schema(request_data, "/zulip-outgoing-webhook", "post", "200") self.assertEqual(request_data["bot_full_name"], self.bot_user.full_name) self.assertEqual(request_data["data"], "@**test**") self.assertEqual(request_data["token"], "abcdef") self.assertEqual(request_data["message"], expected_message_data) # Make sure we didn't accidentally mutate wide_message_dict. self.assertEqual(wide_message_dict["sender_realm_id"], othello.realm_id)