email-templates: Add zulip_onboarding_topics email templates.

The "followup_day2" email template name is not clear or descriptive
about the purpose of the email. Creates a duplicate of those email
template files with the template name "zulip_onboarding_topics".

Because any existing scheduled emails that use the "followup_day2"
templates will need to be updated before the current templates can
be removed, we don't do a simple file rename here.
This commit is contained in:
Lauryn Menard 2023-07-18 11:50:12 +02:00 committed by Tim Abbott
parent c491bef07b
commit 5e29e025c5
9 changed files with 96 additions and 40 deletions

View File

@ -38,7 +38,7 @@ is figuring out how to schedule it. There are 3 ways to schedule email.
email. email.
- Add it to a queue. An example is the `invitation` email. - Add it to a queue. An example is the `invitation` email.
- Send it (approximately) at a specified time in the future, using - Send it (approximately) at a specified time in the future, using
`send_future_email`. An example is the `followup_day2` email. `send_future_email`. An example is the `onboarding_zulip_topics` email.
Email takes about a quarter second per email to process and send. Generally Email takes about a quarter second per email to process and send. Generally
speaking, if you're sending just one email, doing it in the current process speaking, if you're sending just one email, doing it in the current process

View File

@ -0,0 +1,36 @@
{% extends "zerver/emails/email_base_default.html" %}
{% block illustration %}
<img src="{{ email_images_base_url }}/day2_1.png" alt=""/>
{% endblock %}
{% block content %}
<p>
{{ _("Here are some tips for keeping your Zulip conversations organized with topics.") }}
</p>
<p>
{{ _("In Zulip, <b>streams</b> determine who gets a message. <b>Topics</b> tell you what the message is about.")}} {{ _("Using topics, you can read Zulip one conversation at a time. You'll see each message in context, no matter how many different discussions are going on.") }}
</p>
<img class="responsive-width" src="{{ email_images_base_url }}/streams-and-topics.png" alt="{{ _('Streams and topics in the Zulip app') }}"/>
<p>
{{ _("To kick off a new conversation, just pick a stream and start a new topic. This way, the new conversation thread won't interrupt ongoing discussions. For a good topic name, think about finishing the sentence: “Hey, can we chat about…?”") }}
</p>
<img class="responsive-width" src="{{ email_images_base_url }}/day2_2.png" alt="{{ _('Examples of short topics') }}"/>
<p>
{% trans %}Don't stress about picking the perfect name for your topic. If anything is out of place, it's easy to <a href="{{ move_messages_link }}">move messages</a>, <a href="{{ rename_topics_link }}">rename topics</a>, or even <a href="{{ move_topic_to_different_stream_link }}">move a topic to a different stream</a>.{% endtrans %}
</p>
<a class="button" href="{{ realm_uri }}">{{ _("Go to Zulip") }}</a>
{% endblock %}
{% block manage_preferences %}
<p><a href="{{ unsubscribe_link }}">{% trans %}Unsubscribe from welcome emails for {{ realm_name }}{% endtrans %}</a></p>
{% endblock %}

View File

@ -0,0 +1 @@
{{ _("Keep your conversations organized with topics") }}

View File

@ -0,0 +1,15 @@
{{ _("Here are some tips for keeping your Zulip conversations organized with topics.") }}
{{ _("In Zulip, streams determine who gets a message. Topics tell you what the message is about.") }} {{ _("Using topics, you can read Zulip one conversation at a time. You'll see each message in context, no matter how many different discussions are going on.") }}
{{ _("To kick off a new conversation, just pick a stream and start a new topic. This way, the new conversation thread won't interrupt ongoing discussions. For a good topic name, think about finishing the sentence: “Hey, can we chat about…?”") }}
{% trans %}Don't stress about picking the perfect name for your topic. If anything is out of place, it's easy to move messages ({{ move_messages_link }}), rename topics ({{ rename_topics_link }}), or even move a topic to a different stream ({{ move_topic_to_different_stream_link }}).{% endtrans %}
{{ _("Go to Zulip") }}:
<{{ realm_uri }}>
----
{% trans %}Unsubscribe from welcome emails for {{ realm_name }}{% endtrans %}:
{{ unsubscribe_link }}

View File

@ -693,7 +693,7 @@ def get_onboarding_email_schedule(user: UserProfile) -> Dict[str, timedelta]:
# as our goal is to maximize the chance that this email is near the top # as our goal is to maximize the chance that this email is near the top
# of the user's inbox when the user sits down to deal with their inbox, # of the user's inbox when the user sits down to deal with their inbox,
# or comes in while they are dealing with their inbox. # or comes in while they are dealing with their inbox.
"followup_day2": timedelta(days=2, hours=-1), "onboarding_zulip_topics": timedelta(days=2, hours=-1),
"onboarding_zulip_guide": timedelta(days=4, hours=-1), "onboarding_zulip_guide": timedelta(days=4, hours=-1),
} }
@ -708,27 +708,27 @@ def get_onboarding_email_schedule(user: UserProfile) -> Dict[str, timedelta]:
# User signed up on Tuesday # User signed up on Tuesday
if signup_day == 2: if signup_day == 2:
# Send followup_day2 on Thursday # Send onboarding_zulip_topics on Thursday
# Send onboarding_zulip_guide on Monday # Send onboarding_zulip_guide on Monday
onboarding_emails["onboarding_zulip_guide"] = timedelta(days=6, hours=-1) onboarding_emails["onboarding_zulip_guide"] = timedelta(days=6, hours=-1)
# User signed up on Wednesday # User signed up on Wednesday
if signup_day == 3: if signup_day == 3:
# Send followup_day2 on Friday # Send onboarding_zulip_topics on Friday
# Send onboarding_zulip_guide on Tuesday # Send onboarding_zulip_guide on Tuesday
onboarding_emails["onboarding_zulip_guide"] = timedelta(days=6, hours=-1) onboarding_emails["onboarding_zulip_guide"] = timedelta(days=6, hours=-1)
# User signed up on Thursday # User signed up on Thursday
if signup_day == 4: if signup_day == 4:
# Send followup_day2 on Monday # Send onboarding_zulip_topics on Monday
onboarding_emails["followup_day2"] = timedelta(days=4, hours=-1) onboarding_emails["onboarding_zulip_topics"] = timedelta(days=4, hours=-1)
# Send onboarding_zulip_guide on Wednesday # Send onboarding_zulip_guide on Wednesday
onboarding_emails["onboarding_zulip_guide"] = timedelta(days=6, hours=-1) onboarding_emails["onboarding_zulip_guide"] = timedelta(days=6, hours=-1)
# User signed up on Friday # User signed up on Friday
if signup_day == 5: if signup_day == 5:
# Send followup_day2 on Tuesday # Send onboarding_zulip_topics on Tuesday
onboarding_emails["followup_day2"] = timedelta(days=4, hours=-1) onboarding_emails["onboarding_zulip_topics"] = timedelta(days=4, hours=-1)
# Send onboarding_zulip_guide on Thursday # Send onboarding_zulip_guide on Thursday
onboarding_emails["onboarding_zulip_guide"] = timedelta(days=6, hours=-1) onboarding_emails["onboarding_zulip_guide"] = timedelta(days=6, hours=-1)
@ -829,9 +829,9 @@ def enqueue_welcome_emails(user: UserProfile) -> None:
onboarding_email_schedule = get_onboarding_email_schedule(user) onboarding_email_schedule = get_onboarding_email_schedule(user)
if other_account_count == 0: if other_account_count == 0:
followup_day2_context = common_context(user) onboarding_zulip_topics_context = common_context(user)
followup_day2_context.update( onboarding_zulip_topics_context.update(
unsubscribe_link=unsubscribe_link, unsubscribe_link=unsubscribe_link,
move_messages_link=realm_url + "/help/move-content-to-another-topic", move_messages_link=realm_url + "/help/move-content-to-another-topic",
rename_topics_link=realm_url + "/help/rename-a-topic", rename_topics_link=realm_url + "/help/rename-a-topic",
@ -839,13 +839,13 @@ def enqueue_welcome_emails(user: UserProfile) -> None:
) )
send_future_email( send_future_email(
"zerver/emails/followup_day2", "zerver/emails/onboarding_zulip_topics",
user.realm, user.realm,
to_user_ids=[user.id], to_user_ids=[user.id],
from_name=from_name, from_name=from_name,
from_address=from_address, from_address=from_address,
context=followup_day2_context, context=onboarding_zulip_topics_context,
delay=onboarding_email_schedule["followup_day2"], delay=onboarding_email_schedule["onboarding_zulip_topics"],
) )
# We only send the onboarding_zulip_guide email for a subset of Realm.ORG_TYPES # We only send the onboarding_zulip_guide email for a subset of Realm.ORG_TYPES
@ -863,7 +863,7 @@ def enqueue_welcome_emails(user: UserProfile) -> None:
if onboarding_zulip_guide_url is not None: if onboarding_zulip_guide_url is not None:
onboarding_zulip_guide_context = common_context(user) onboarding_zulip_guide_context = common_context(user)
onboarding_zulip_guide_context.update( onboarding_zulip_guide_context.update(
# We use the same unsubscribe link in both followup_day2 # We use the same unsubscribe link in both onboarding_zulip_topics
# and onboarding_zulip_guide as these links do not expire. # and onboarding_zulip_guide as these links do not expire.
unsubscribe_link=unsubscribe_link, unsubscribe_link=unsubscribe_link,
organization_type=organization_type_reference, organization_type=organization_type_reference,

View File

@ -4423,6 +4423,7 @@ class ScheduledMessage(models.Model):
EMAIL_TYPES = { EMAIL_TYPES = {
"account_registered": ScheduledEmail.WELCOME, "account_registered": ScheduledEmail.WELCOME,
"onboarding_zulip_topics": ScheduledEmail.WELCOME,
"followup_day1": ScheduledEmail.WELCOME, "followup_day1": ScheduledEmail.WELCOME,
"followup_day2": ScheduledEmail.WELCOME, "followup_day2": ScheduledEmail.WELCOME,
"onboarding_zulip_guide": ScheduledEmail.WELCOME, "onboarding_zulip_guide": ScheduledEmail.WELCOME,

View File

@ -386,7 +386,8 @@ class TestFollowupEmails(ZulipTestCase):
"zerver/emails/account_registered", "zerver/emails/account_registered",
) )
self.assertEqual( self.assertEqual(
orjson.loads(scheduled_emails[1].data)["template_prefix"], "zerver/emails/followup_day2" orjson.loads(scheduled_emails[1].data)["template_prefix"],
"zerver/emails/onboarding_zulip_topics",
) )
self.assertEqual( self.assertEqual(
orjson.loads(scheduled_emails[2].data)["template_prefix"], orjson.loads(scheduled_emails[2].data)["template_prefix"],
@ -412,7 +413,8 @@ class TestFollowupEmails(ZulipTestCase):
"zerver/emails/account_registered", "zerver/emails/account_registered",
) )
self.assertEqual( self.assertEqual(
orjson.loads(scheduled_emails[1].data)["template_prefix"], "zerver/emails/followup_day2" orjson.loads(scheduled_emails[1].data)["template_prefix"],
"zerver/emails/onboarding_zulip_topics",
) )
ScheduledEmail.objects.all().delete() ScheduledEmail.objects.all().delete()
@ -427,7 +429,8 @@ class TestFollowupEmails(ZulipTestCase):
"zerver/emails/account_registered", "zerver/emails/account_registered",
) )
self.assertEqual( self.assertEqual(
orjson.loads(scheduled_emails[1].data)["template_prefix"], "zerver/emails/followup_day2" orjson.loads(scheduled_emails[1].data)["template_prefix"],
"zerver/emails/onboarding_zulip_topics",
) )
self.assertEqual( self.assertEqual(
orjson.loads(scheduled_emails[2].data)["template_prefix"], orjson.loads(scheduled_emails[2].data)["template_prefix"],
@ -574,9 +577,9 @@ class TestFollowupEmailDelay(ZulipTestCase):
user_profile.date_joined = dates_joined["Monday"] user_profile.date_joined = dates_joined["Monday"]
onboarding_email_schedule = get_onboarding_email_schedule(user_profile) onboarding_email_schedule = get_onboarding_email_schedule(user_profile)
# followup_day2 email sent on Wednesday # onboarding_zulip_topics email sent on Wednesday
self.assertEqual( self.assertEqual(
onboarding_email_schedule["followup_day2"], onboarding_email_schedule["onboarding_zulip_topics"],
days_delayed["2"], days_delayed["2"],
) )
self.assertEqual((dates_joined["Monday"] + days_delayed["2"]).isoweekday(), 3) self.assertEqual((dates_joined["Monday"] + days_delayed["2"]).isoweekday(), 3)
@ -592,9 +595,9 @@ class TestFollowupEmailDelay(ZulipTestCase):
user_profile.date_joined = dates_joined["Tuesday"] user_profile.date_joined = dates_joined["Tuesday"]
onboarding_email_schedule = get_onboarding_email_schedule(user_profile) onboarding_email_schedule = get_onboarding_email_schedule(user_profile)
# followup_day2 email sent on Thursday # onboarding_zulip_topics email sent on Thursday
self.assertEqual( self.assertEqual(
onboarding_email_schedule["followup_day2"], onboarding_email_schedule["onboarding_zulip_topics"],
days_delayed["2"], days_delayed["2"],
) )
self.assertEqual((dates_joined["Tuesday"] + days_delayed["2"]).isoweekday(), 4) self.assertEqual((dates_joined["Tuesday"] + days_delayed["2"]).isoweekday(), 4)
@ -610,9 +613,9 @@ class TestFollowupEmailDelay(ZulipTestCase):
user_profile.date_joined = dates_joined["Wednesday"] user_profile.date_joined = dates_joined["Wednesday"]
onboarding_email_schedule = get_onboarding_email_schedule(user_profile) onboarding_email_schedule = get_onboarding_email_schedule(user_profile)
# followup_day2 email sent on Friday # onboarding_zulip_topics email sent on Friday
self.assertEqual( self.assertEqual(
onboarding_email_schedule["followup_day2"], onboarding_email_schedule["onboarding_zulip_topics"],
days_delayed["2"], days_delayed["2"],
) )
self.assertEqual((dates_joined["Wednesday"] + days_delayed["2"]).isoweekday(), 5) self.assertEqual((dates_joined["Wednesday"] + days_delayed["2"]).isoweekday(), 5)
@ -628,9 +631,9 @@ class TestFollowupEmailDelay(ZulipTestCase):
user_profile.date_joined = dates_joined["Thursday"] user_profile.date_joined = dates_joined["Thursday"]
onboarding_email_schedule = get_onboarding_email_schedule(user_profile) onboarding_email_schedule = get_onboarding_email_schedule(user_profile)
# followup_day2 email sent on Monday # onboarding_zulip_topics email sent on Monday
self.assertEqual( self.assertEqual(
onboarding_email_schedule["followup_day2"], onboarding_email_schedule["onboarding_zulip_topics"],
days_delayed["4"], days_delayed["4"],
) )
self.assertEqual((dates_joined["Thursday"] + days_delayed["4"]).isoweekday(), 1) self.assertEqual((dates_joined["Thursday"] + days_delayed["4"]).isoweekday(), 1)
@ -646,9 +649,9 @@ class TestFollowupEmailDelay(ZulipTestCase):
user_profile.date_joined = dates_joined["Friday"] user_profile.date_joined = dates_joined["Friday"]
onboarding_email_schedule = get_onboarding_email_schedule(user_profile) onboarding_email_schedule = get_onboarding_email_schedule(user_profile)
# followup_day2 email sent on Tuesday # onboarding_zulip_topics email sent on Tuesday
self.assertEqual( self.assertEqual(
onboarding_email_schedule["followup_day2"], onboarding_email_schedule["onboarding_zulip_topics"],
days_delayed["4"], days_delayed["4"],
) )
self.assertEqual((dates_joined["Friday"] + days_delayed["4"]).isoweekday(), 2) self.assertEqual((dates_joined["Friday"] + days_delayed["4"]).isoweekday(), 2)
@ -664,9 +667,9 @@ class TestFollowupEmailDelay(ZulipTestCase):
user_profile.date_joined = dates_joined["Saturday"] user_profile.date_joined = dates_joined["Saturday"]
onboarding_email_schedule = get_onboarding_email_schedule(user_profile) onboarding_email_schedule = get_onboarding_email_schedule(user_profile)
# followup_day2 email sent on Monday # onboarding_zulip_topics email sent on Monday
self.assertEqual( self.assertEqual(
onboarding_email_schedule["followup_day2"], onboarding_email_schedule["onboarding_zulip_topics"],
days_delayed["2"], days_delayed["2"],
) )
self.assertEqual((dates_joined["Saturday"] + days_delayed["2"]).isoweekday(), 1) self.assertEqual((dates_joined["Saturday"] + days_delayed["2"]).isoweekday(), 1)
@ -682,9 +685,9 @@ class TestFollowupEmailDelay(ZulipTestCase):
user_profile.date_joined = dates_joined["Sunday"] user_profile.date_joined = dates_joined["Sunday"]
onboarding_email_schedule = get_onboarding_email_schedule(user_profile) onboarding_email_schedule = get_onboarding_email_schedule(user_profile)
# followup_day2 email sent on Tuesday # onboarding_zulip_topics email sent on Tuesday
self.assertEqual( self.assertEqual(
onboarding_email_schedule["followup_day2"], onboarding_email_schedule["onboarding_zulip_topics"],
days_delayed["2"], days_delayed["2"],
) )
self.assertEqual((dates_joined["Sunday"] + days_delayed["2"]).isoweekday(), 2) self.assertEqual((dates_joined["Sunday"] + days_delayed["2"]).isoweekday(), 2)
@ -703,9 +706,9 @@ class TestFollowupEmailDelay(ZulipTestCase):
user_profile.date_joined = datetime(2018, 1, 5, 1, 0, 0, 0, tzinfo=timezone.utc) user_profile.date_joined = datetime(2018, 1, 5, 1, 0, 0, 0, tzinfo=timezone.utc)
onboarding_email_schedule = get_onboarding_email_schedule(user_profile) onboarding_email_schedule = get_onboarding_email_schedule(user_profile)
# followup_day2 email sent on Monday # onboarding_zulip_topics email sent on Monday
self.assertEqual( self.assertEqual(
onboarding_email_schedule["followup_day2"], onboarding_email_schedule["onboarding_zulip_topics"],
days_delayed["4"], days_delayed["4"],
) )

View File

@ -323,7 +323,7 @@ class RealmTest(ZulipTestCase):
def test_do_deactivate_realm_clears_scheduled_jobs(self) -> None: def test_do_deactivate_realm_clears_scheduled_jobs(self) -> None:
user = self.example_user("hamlet") user = self.example_user("hamlet")
send_future_email( send_future_email(
"zerver/emails/followup_day2", "zerver/emails/onboarding_zulip_topics",
user.realm, user.realm,
to_user_ids=[user.id], to_user_ids=[user.id],
delay=datetime.timedelta(hours=1), delay=datetime.timedelta(hours=1),

View File

@ -1699,7 +1699,7 @@ class ActivateTest(ZulipTestCase):
def test_clear_scheduled_jobs(self) -> None: def test_clear_scheduled_jobs(self) -> None:
user = self.example_user("hamlet") user = self.example_user("hamlet")
send_future_email( send_future_email(
"zerver/emails/followup_day2", "zerver/emails/onboarding_zulip_topics",
user.realm, user.realm,
to_user_ids=[user.id], to_user_ids=[user.id],
delay=datetime.timedelta(hours=1), delay=datetime.timedelta(hours=1),
@ -1712,7 +1712,7 @@ class ActivateTest(ZulipTestCase):
hamlet = self.example_user("hamlet") hamlet = self.example_user("hamlet")
iago = self.example_user("iago") iago = self.example_user("iago")
send_future_email( send_future_email(
"zerver/emails/followup_day2", "zerver/emails/onboarding_zulip_topics",
iago.realm, iago.realm,
to_user_ids=[hamlet.id, iago.id], to_user_ids=[hamlet.id, iago.id],
delay=datetime.timedelta(hours=1), delay=datetime.timedelta(hours=1),
@ -1728,7 +1728,7 @@ class ActivateTest(ZulipTestCase):
hamlet = self.example_user("hamlet") hamlet = self.example_user("hamlet")
iago = self.example_user("iago") iago = self.example_user("iago")
send_future_email( send_future_email(
"zerver/emails/followup_day2", "zerver/emails/onboarding_zulip_topics",
iago.realm, iago.realm,
to_user_ids=[hamlet.id, iago.id], to_user_ids=[hamlet.id, iago.id],
delay=datetime.timedelta(hours=1), delay=datetime.timedelta(hours=1),
@ -1743,7 +1743,7 @@ class ActivateTest(ZulipTestCase):
iago = self.example_user("iago") iago = self.example_user("iago")
hamlet = self.example_user("hamlet") hamlet = self.example_user("hamlet")
send_future_email( send_future_email(
"zerver/emails/followup_day2", "zerver/emails/onboarding_zulip_topics",
iago.realm, iago.realm,
to_user_ids=[hamlet.id, iago.id], to_user_ids=[hamlet.id, iago.id],
delay=datetime.timedelta(hours=1), delay=datetime.timedelta(hours=1),
@ -1769,7 +1769,7 @@ class ActivateTest(ZulipTestCase):
hamlet = self.example_user("hamlet") hamlet = self.example_user("hamlet")
to_user_ids = [hamlet.id, iago.id] to_user_ids = [hamlet.id, iago.id]
send_future_email( send_future_email(
"zerver/emails/followup_day2", "zerver/emails/onboarding_zulip_topics",
iago.realm, iago.realm,
to_user_ids=to_user_ids, to_user_ids=to_user_ids,
delay=datetime.timedelta(hours=1), delay=datetime.timedelta(hours=1),
@ -1792,7 +1792,7 @@ class ActivateTest(ZulipTestCase):
[ [
f"WARNING:zulip.send_email:ScheduledEmail {email_id} at {scheduled_at} " f"WARNING:zulip.send_email:ScheduledEmail {email_id} at {scheduled_at} "
"had empty users and address attributes: " "had empty users and address attributes: "
"{'template_prefix': 'zerver/emails/followup_day2', 'from_name': None, " "{'template_prefix': 'zerver/emails/onboarding_zulip_topics', 'from_name': None, "
"'from_address': None, 'language': None, 'context': {}}" "'from_address': None, 'language': None, 'context': {}}"
], ],
) )