mirror of
https://github.com/zulip/zulip.git
synced 2025-11-06 15:03:34 +00:00
Annotate zerver/lib/notifications.py.
This commit is contained in:
@@ -1,15 +1,25 @@
|
||||
from __future__ import print_function
|
||||
from typing import Any, Tuple
|
||||
from typing import Any, Tuple, Iterable, Optional
|
||||
|
||||
import mandrill
|
||||
from confirmation.models import Confirmation
|
||||
from django.conf import settings
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.template import loader
|
||||
from zerver.decorator import statsd_increment, uses_mandrill
|
||||
from zerver.models import Recipient, ScheduledJob, UserMessage, \
|
||||
Stream, get_display_recipient, get_user_profile_by_email, \
|
||||
get_user_profile_by_id, receives_offline_notifications, \
|
||||
get_context_for_message, Message
|
||||
from zerver.models import (
|
||||
Recipient,
|
||||
ScheduledJob,
|
||||
UserMessage,
|
||||
Stream,
|
||||
get_display_recipient,
|
||||
UserProfile,
|
||||
get_user_profile_by_email,
|
||||
get_user_profile_by_id,
|
||||
receives_offline_notifications,
|
||||
get_context_for_message,
|
||||
Message
|
||||
)
|
||||
|
||||
import datetime
|
||||
import re
|
||||
@@ -19,11 +29,13 @@ from six.moves import urllib
|
||||
from collections import defaultdict
|
||||
|
||||
def unsubscribe_token(user_profile):
|
||||
# type: (UserProfile) -> str
|
||||
# Leverage the Django confirmations framework to generate and track unique
|
||||
# unsubscription tokens.
|
||||
return Confirmation.objects.get_link_for_object(user_profile).split("/")[-1]
|
||||
|
||||
def one_click_unsubscribe_link(user_profile, endpoint):
|
||||
# type: (UserProfile, str) -> str
|
||||
"""
|
||||
Generate a unique link that a logged-out user can visit to unsubscribe from
|
||||
Zulip e-mails without having to first log in.
|
||||
@@ -34,6 +46,7 @@ def one_click_unsubscribe_link(user_profile, endpoint):
|
||||
return "%s/%s" % (base_url.rstrip("/"), resource_path)
|
||||
|
||||
def hashchange_encode(string):
|
||||
# type: (str) -> str
|
||||
# Do the same encoding operation as hashchange.encodeHashComponent on the
|
||||
# frontend.
|
||||
# `safe` has a default value of "/", but we want those encoded, too.
|
||||
@@ -41,20 +54,24 @@ def hashchange_encode(string):
|
||||
string.encode("utf-8"), safe="").replace(".", "%2E").replace("%", ".")
|
||||
|
||||
def pm_narrow_url(participants):
|
||||
# type: (List[str]) -> str
|
||||
participants.sort()
|
||||
base_url = "https://%s/#narrow/pm-with/" % (settings.EXTERNAL_HOST,)
|
||||
return base_url + hashchange_encode(",".join(participants))
|
||||
|
||||
def stream_narrow_url(stream):
|
||||
# type: (str) -> str
|
||||
base_url = "https://%s/#narrow/stream/" % (settings.EXTERNAL_HOST,)
|
||||
return base_url + hashchange_encode(stream)
|
||||
|
||||
def topic_narrow_url(stream, topic):
|
||||
# type: (str, str) -> str
|
||||
base_url = "https://%s/#narrow/stream/" % (settings.EXTERNAL_HOST,)
|
||||
return "%s%s/topic/%s" % (base_url, hashchange_encode(stream),
|
||||
hashchange_encode(topic))
|
||||
|
||||
def build_message_list(user_profile, messages):
|
||||
# type: (UserProfile, List[Message]) -> List[Dict[str, Any]]
|
||||
"""
|
||||
Builds the message list object for the missed message email template.
|
||||
The messages are collapsed into per-recipient and per-sender blocks, like
|
||||
@@ -63,12 +80,14 @@ def build_message_list(user_profile, messages):
|
||||
messages_to_render = [] # type: List[Dict[str, Any]]
|
||||
|
||||
def sender_string(message):
|
||||
# type: (Message) -> str
|
||||
sender = ''
|
||||
if message.recipient.type in (Recipient.STREAM, Recipient.HUDDLE):
|
||||
sender = message.sender.full_name
|
||||
return sender
|
||||
|
||||
def relative_to_full_url(content):
|
||||
# type: (str) -> str
|
||||
# URLs for uploaded content are of the form
|
||||
# "/user_uploads/abc.png". Make them full paths.
|
||||
#
|
||||
@@ -94,15 +113,18 @@ def build_message_list(user_profile, messages):
|
||||
return content
|
||||
|
||||
def fix_plaintext_image_urls(content):
|
||||
# type: (str) -> str
|
||||
# Replace image URLs in plaintext content of the form
|
||||
# [image name](image url)
|
||||
# with a simple hyperlink.
|
||||
return re.sub(r"\[(\S*)\]\((\S*)\)", r"\2", content)
|
||||
|
||||
def fix_emoji_sizes(html):
|
||||
# type: (str) -> str
|
||||
return html.replace(' class="emoji"', ' height="20px"')
|
||||
|
||||
def build_message_payload(message):
|
||||
# type: (Message) -> Dict[str, str]
|
||||
plain = message.content
|
||||
plain = fix_plaintext_image_urls(plain)
|
||||
plain = relative_to_full_url(plain)
|
||||
@@ -114,11 +136,13 @@ def build_message_list(user_profile, messages):
|
||||
return {'plain': plain, 'html': html}
|
||||
|
||||
def build_sender_payload(message):
|
||||
# type: (Message) -> Dict[str, Any]
|
||||
sender = sender_string(message)
|
||||
return {'sender': sender,
|
||||
'content': [build_message_payload(message)]}
|
||||
|
||||
def message_header(user_profile, message):
|
||||
# type: (UserProfile, Message) -> Dict[str, str]
|
||||
disp_recipient = get_display_recipient(message.recipient)
|
||||
if message.recipient.type == Recipient.PERSONAL:
|
||||
header = "You and %s" % (message.sender.full_name)
|
||||
@@ -193,6 +217,7 @@ def build_message_list(user_profile, messages):
|
||||
|
||||
@statsd_increment("missed_message_reminders")
|
||||
def do_send_missedmessage_events_reply_in_zulip(user_profile, missed_messages, message_count):
|
||||
# type: (UserProfile, List[Message], int) -> None
|
||||
"""
|
||||
Send a reminder email to a user if she's missed some PMs by being offline.
|
||||
|
||||
@@ -252,6 +277,7 @@ def do_send_missedmessage_events_reply_in_zulip(user_profile, missed_messages, m
|
||||
|
||||
@statsd_increment("missed_message_reminders")
|
||||
def do_send_missedmessage_events(user_profile, missed_messages, message_count):
|
||||
# type: (UserProfile, List[Message], int) -> None
|
||||
"""
|
||||
Send a reminder email and/or push notifications to a user if she's missed some PMs by being offline
|
||||
|
||||
@@ -314,6 +340,7 @@ def do_send_missedmessage_events(user_profile, missed_messages, message_count):
|
||||
|
||||
|
||||
def handle_missedmessage_emails(user_profile_id, missed_email_events):
|
||||
# type: (int, Iterable[Dict[str, Any]]) -> None
|
||||
message_ids = [event.get('message_id') for event in missed_email_events]
|
||||
|
||||
user_profile = get_user_profile_by_id(user_profile_id)
|
||||
@@ -364,6 +391,7 @@ def handle_missedmessage_emails(user_profile_id, missed_email_events):
|
||||
|
||||
@uses_mandrill
|
||||
def clear_followup_emails_queue(email, mail_client=None):
|
||||
# type: (str, Optional[mandrill.Mandrill]) -> None
|
||||
"""
|
||||
Clear out queued emails (from Mandrill's queue) that would otherwise
|
||||
be sent to a specific email address. Optionally specify which sender
|
||||
@@ -388,6 +416,7 @@ def clear_followup_emails_queue(email, mail_client=None):
|
||||
return
|
||||
|
||||
def log_digest_event(msg):
|
||||
# type: (str) -> None
|
||||
import logging
|
||||
logging.basicConfig(filename=settings.DIGEST_LOG_PATH, level=logging.INFO)
|
||||
logging.info(msg)
|
||||
@@ -396,6 +425,7 @@ def log_digest_event(msg):
|
||||
def send_future_email(recipients, email_html, email_text, subject,
|
||||
delay=datetime.timedelta(0), sender=None,
|
||||
tags=[], mail_client=None):
|
||||
# type: (List[Dict[str, Any]], str, str, str, datetime.timedelta, Optional[Dict[str, str]], Iterable[str], Optional[mandrill.Mandrill]) -> None
|
||||
"""
|
||||
Sends email via Mandrill, with optional delay
|
||||
|
||||
@@ -483,6 +513,7 @@ def send_future_email(recipients, email_html, email_text, subject,
|
||||
def send_local_email_template_with_delay(recipients, template_prefix,
|
||||
template_payload, delay,
|
||||
tags=[], sender={'email': settings.NOREPLY_EMAIL_ADDRESS, 'name': 'Zulip'}):
|
||||
# type: (List[Dict[str, Any]], str, Dict[str, str], datetime.timedelta, Iterable[str], Dict[str, str]) -> None
|
||||
html_content = loader.render_to_string(template_prefix + ".html", template_payload)
|
||||
text_content = loader.render_to_string(template_prefix + ".text", template_payload)
|
||||
subject = loader.render_to_string(template_prefix + ".subject", template_payload).strip()
|
||||
@@ -496,6 +527,7 @@ def send_local_email_template_with_delay(recipients, template_prefix,
|
||||
tags=tags)
|
||||
|
||||
def enqueue_welcome_emails(email, name):
|
||||
# type: (str, str) -> None
|
||||
sender = {'email': 'wdaher@zulip.com', 'name': 'Waseem Daher'}
|
||||
if settings.VOYAGER:
|
||||
sender = {'email': settings.ZULIP_ADMINISTRATOR, 'name': 'Zulip'}
|
||||
@@ -528,6 +560,7 @@ def enqueue_welcome_emails(email, name):
|
||||
sender=sender)
|
||||
|
||||
def convert_html_to_markdown(html):
|
||||
# type: (str) -> unicode
|
||||
# On Linux, the tool installs as html2markdown, and there's a command called
|
||||
# html2text that does something totally different. On OSX, the tool installs
|
||||
# as html2text.
|
||||
|
||||
Reference in New Issue
Block a user