From 5e29e025c53b00a97b17c26f6021aa5c43254a66 Mon Sep 17 00:00:00 2001 From: Lauryn Menard Date: Tue, 18 Jul 2023 11:50:12 +0200 Subject: [PATCH] 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. --- docs/subsystems/email.md | 2 +- .../emails/onboarding_zulip_topics.html | 36 ++++++++++++++++ .../onboarding_zulip_topics.subject.txt | 1 + .../zerver/emails/onboarding_zulip_topics.txt | 15 +++++++ zerver/lib/email_notifications.py | 26 ++++++------ zerver/models.py | 1 + zerver/tests/test_email_notifications.py | 41 ++++++++++--------- zerver/tests/test_realm.py | 2 +- zerver/tests/test_users.py | 12 +++--- 9 files changed, 96 insertions(+), 40 deletions(-) create mode 100644 templates/zerver/emails/onboarding_zulip_topics.html create mode 100644 templates/zerver/emails/onboarding_zulip_topics.subject.txt create mode 100644 templates/zerver/emails/onboarding_zulip_topics.txt diff --git a/docs/subsystems/email.md b/docs/subsystems/email.md index 0c00974a7c..322e9cf034 100644 --- a/docs/subsystems/email.md +++ b/docs/subsystems/email.md @@ -38,7 +38,7 @@ is figuring out how to schedule it. There are 3 ways to schedule email. email. - Add it to a queue. An example is the `invitation` email. - 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 speaking, if you're sending just one email, doing it in the current process diff --git a/templates/zerver/emails/onboarding_zulip_topics.html b/templates/zerver/emails/onboarding_zulip_topics.html new file mode 100644 index 0000000000..8e61cdcd56 --- /dev/null +++ b/templates/zerver/emails/onboarding_zulip_topics.html @@ -0,0 +1,36 @@ +{% extends "zerver/emails/email_base_default.html" %} + +{% block illustration %} + +{% endblock %} + +{% block content %} +

+ {{ _("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.") }} +

+ +{{ _('Streams and topics in the Zulip app') }} + +

+ {{ _("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…?”") }} +

+ +{{ _('Examples of short topics') }} + +

+ {% trans %}Don't stress about picking the perfect name for your topic. If anything is out of place, it's easy to move messages, rename topics, or even move a topic to a different stream.{% endtrans %} +

+ +{{ _("Go to Zulip") }} + +{% endblock %} + +{% block manage_preferences %} + +

{% trans %}Unsubscribe from welcome emails for {{ realm_name }}{% endtrans %}

+ +{% endblock %} diff --git a/templates/zerver/emails/onboarding_zulip_topics.subject.txt b/templates/zerver/emails/onboarding_zulip_topics.subject.txt new file mode 100644 index 0000000000..bbdf3db632 --- /dev/null +++ b/templates/zerver/emails/onboarding_zulip_topics.subject.txt @@ -0,0 +1 @@ +{{ _("Keep your conversations organized with topics") }} diff --git a/templates/zerver/emails/onboarding_zulip_topics.txt b/templates/zerver/emails/onboarding_zulip_topics.txt new file mode 100644 index 0000000000..2942f0cc00 --- /dev/null +++ b/templates/zerver/emails/onboarding_zulip_topics.txt @@ -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 }} diff --git a/zerver/lib/email_notifications.py b/zerver/lib/email_notifications.py index 96cf94205d..9b07570c9e 100644 --- a/zerver/lib/email_notifications.py +++ b/zerver/lib/email_notifications.py @@ -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 # 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. - "followup_day2": timedelta(days=2, hours=-1), + "onboarding_zulip_topics": timedelta(days=2, 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 if signup_day == 2: - # Send followup_day2 on Thursday + # Send onboarding_zulip_topics on Thursday # Send onboarding_zulip_guide on Monday onboarding_emails["onboarding_zulip_guide"] = timedelta(days=6, hours=-1) # User signed up on Wednesday if signup_day == 3: - # Send followup_day2 on Friday + # Send onboarding_zulip_topics on Friday # Send onboarding_zulip_guide on Tuesday onboarding_emails["onboarding_zulip_guide"] = timedelta(days=6, hours=-1) # User signed up on Thursday if signup_day == 4: - # Send followup_day2 on Monday - onboarding_emails["followup_day2"] = timedelta(days=4, hours=-1) + # Send onboarding_zulip_topics on Monday + onboarding_emails["onboarding_zulip_topics"] = timedelta(days=4, hours=-1) # Send onboarding_zulip_guide on Wednesday onboarding_emails["onboarding_zulip_guide"] = timedelta(days=6, hours=-1) # User signed up on Friday if signup_day == 5: - # Send followup_day2 on Tuesday - onboarding_emails["followup_day2"] = timedelta(days=4, hours=-1) + # Send onboarding_zulip_topics on Tuesday + onboarding_emails["onboarding_zulip_topics"] = timedelta(days=4, hours=-1) # Send onboarding_zulip_guide on Thursday 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) 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, move_messages_link=realm_url + "/help/move-content-to-another-topic", rename_topics_link=realm_url + "/help/rename-a-topic", @@ -839,13 +839,13 @@ def enqueue_welcome_emails(user: UserProfile) -> None: ) send_future_email( - "zerver/emails/followup_day2", + "zerver/emails/onboarding_zulip_topics", user.realm, to_user_ids=[user.id], from_name=from_name, from_address=from_address, - context=followup_day2_context, - delay=onboarding_email_schedule["followup_day2"], + context=onboarding_zulip_topics_context, + delay=onboarding_email_schedule["onboarding_zulip_topics"], ) # 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: onboarding_zulip_guide_context = common_context(user) 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. unsubscribe_link=unsubscribe_link, organization_type=organization_type_reference, diff --git a/zerver/models.py b/zerver/models.py index 858756bd81..683bc5e0a0 100644 --- a/zerver/models.py +++ b/zerver/models.py @@ -4423,6 +4423,7 @@ class ScheduledMessage(models.Model): EMAIL_TYPES = { "account_registered": ScheduledEmail.WELCOME, + "onboarding_zulip_topics": ScheduledEmail.WELCOME, "followup_day1": ScheduledEmail.WELCOME, "followup_day2": ScheduledEmail.WELCOME, "onboarding_zulip_guide": ScheduledEmail.WELCOME, diff --git a/zerver/tests/test_email_notifications.py b/zerver/tests/test_email_notifications.py index 3c9f300c0e..05ff3204aa 100644 --- a/zerver/tests/test_email_notifications.py +++ b/zerver/tests/test_email_notifications.py @@ -386,7 +386,8 @@ class TestFollowupEmails(ZulipTestCase): "zerver/emails/account_registered", ) 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( orjson.loads(scheduled_emails[2].data)["template_prefix"], @@ -412,7 +413,8 @@ class TestFollowupEmails(ZulipTestCase): "zerver/emails/account_registered", ) 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() @@ -427,7 +429,8 @@ class TestFollowupEmails(ZulipTestCase): "zerver/emails/account_registered", ) 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( orjson.loads(scheduled_emails[2].data)["template_prefix"], @@ -574,9 +577,9 @@ class TestFollowupEmailDelay(ZulipTestCase): user_profile.date_joined = dates_joined["Monday"] onboarding_email_schedule = get_onboarding_email_schedule(user_profile) - # followup_day2 email sent on Wednesday + # onboarding_zulip_topics email sent on Wednesday self.assertEqual( - onboarding_email_schedule["followup_day2"], + onboarding_email_schedule["onboarding_zulip_topics"], days_delayed["2"], ) self.assertEqual((dates_joined["Monday"] + days_delayed["2"]).isoweekday(), 3) @@ -592,9 +595,9 @@ class TestFollowupEmailDelay(ZulipTestCase): user_profile.date_joined = dates_joined["Tuesday"] onboarding_email_schedule = get_onboarding_email_schedule(user_profile) - # followup_day2 email sent on Thursday + # onboarding_zulip_topics email sent on Thursday self.assertEqual( - onboarding_email_schedule["followup_day2"], + onboarding_email_schedule["onboarding_zulip_topics"], days_delayed["2"], ) self.assertEqual((dates_joined["Tuesday"] + days_delayed["2"]).isoweekday(), 4) @@ -610,9 +613,9 @@ class TestFollowupEmailDelay(ZulipTestCase): user_profile.date_joined = dates_joined["Wednesday"] onboarding_email_schedule = get_onboarding_email_schedule(user_profile) - # followup_day2 email sent on Friday + # onboarding_zulip_topics email sent on Friday self.assertEqual( - onboarding_email_schedule["followup_day2"], + onboarding_email_schedule["onboarding_zulip_topics"], days_delayed["2"], ) self.assertEqual((dates_joined["Wednesday"] + days_delayed["2"]).isoweekday(), 5) @@ -628,9 +631,9 @@ class TestFollowupEmailDelay(ZulipTestCase): user_profile.date_joined = dates_joined["Thursday"] onboarding_email_schedule = get_onboarding_email_schedule(user_profile) - # followup_day2 email sent on Monday + # onboarding_zulip_topics email sent on Monday self.assertEqual( - onboarding_email_schedule["followup_day2"], + onboarding_email_schedule["onboarding_zulip_topics"], days_delayed["4"], ) self.assertEqual((dates_joined["Thursday"] + days_delayed["4"]).isoweekday(), 1) @@ -646,9 +649,9 @@ class TestFollowupEmailDelay(ZulipTestCase): user_profile.date_joined = dates_joined["Friday"] onboarding_email_schedule = get_onboarding_email_schedule(user_profile) - # followup_day2 email sent on Tuesday + # onboarding_zulip_topics email sent on Tuesday self.assertEqual( - onboarding_email_schedule["followup_day2"], + onboarding_email_schedule["onboarding_zulip_topics"], days_delayed["4"], ) self.assertEqual((dates_joined["Friday"] + days_delayed["4"]).isoweekday(), 2) @@ -664,9 +667,9 @@ class TestFollowupEmailDelay(ZulipTestCase): user_profile.date_joined = dates_joined["Saturday"] onboarding_email_schedule = get_onboarding_email_schedule(user_profile) - # followup_day2 email sent on Monday + # onboarding_zulip_topics email sent on Monday self.assertEqual( - onboarding_email_schedule["followup_day2"], + onboarding_email_schedule["onboarding_zulip_topics"], days_delayed["2"], ) self.assertEqual((dates_joined["Saturday"] + days_delayed["2"]).isoweekday(), 1) @@ -682,9 +685,9 @@ class TestFollowupEmailDelay(ZulipTestCase): user_profile.date_joined = dates_joined["Sunday"] onboarding_email_schedule = get_onboarding_email_schedule(user_profile) - # followup_day2 email sent on Tuesday + # onboarding_zulip_topics email sent on Tuesday self.assertEqual( - onboarding_email_schedule["followup_day2"], + onboarding_email_schedule["onboarding_zulip_topics"], days_delayed["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) onboarding_email_schedule = get_onboarding_email_schedule(user_profile) - # followup_day2 email sent on Monday + # onboarding_zulip_topics email sent on Monday self.assertEqual( - onboarding_email_schedule["followup_day2"], + onboarding_email_schedule["onboarding_zulip_topics"], days_delayed["4"], ) diff --git a/zerver/tests/test_realm.py b/zerver/tests/test_realm.py index 44accf58d8..3f199ef25d 100644 --- a/zerver/tests/test_realm.py +++ b/zerver/tests/test_realm.py @@ -323,7 +323,7 @@ class RealmTest(ZulipTestCase): def test_do_deactivate_realm_clears_scheduled_jobs(self) -> None: user = self.example_user("hamlet") send_future_email( - "zerver/emails/followup_day2", + "zerver/emails/onboarding_zulip_topics", user.realm, to_user_ids=[user.id], delay=datetime.timedelta(hours=1), diff --git a/zerver/tests/test_users.py b/zerver/tests/test_users.py index 965e1c69b8..98297be732 100644 --- a/zerver/tests/test_users.py +++ b/zerver/tests/test_users.py @@ -1699,7 +1699,7 @@ class ActivateTest(ZulipTestCase): def test_clear_scheduled_jobs(self) -> None: user = self.example_user("hamlet") send_future_email( - "zerver/emails/followup_day2", + "zerver/emails/onboarding_zulip_topics", user.realm, to_user_ids=[user.id], delay=datetime.timedelta(hours=1), @@ -1712,7 +1712,7 @@ class ActivateTest(ZulipTestCase): hamlet = self.example_user("hamlet") iago = self.example_user("iago") send_future_email( - "zerver/emails/followup_day2", + "zerver/emails/onboarding_zulip_topics", iago.realm, to_user_ids=[hamlet.id, iago.id], delay=datetime.timedelta(hours=1), @@ -1728,7 +1728,7 @@ class ActivateTest(ZulipTestCase): hamlet = self.example_user("hamlet") iago = self.example_user("iago") send_future_email( - "zerver/emails/followup_day2", + "zerver/emails/onboarding_zulip_topics", iago.realm, to_user_ids=[hamlet.id, iago.id], delay=datetime.timedelta(hours=1), @@ -1743,7 +1743,7 @@ class ActivateTest(ZulipTestCase): iago = self.example_user("iago") hamlet = self.example_user("hamlet") send_future_email( - "zerver/emails/followup_day2", + "zerver/emails/onboarding_zulip_topics", iago.realm, to_user_ids=[hamlet.id, iago.id], delay=datetime.timedelta(hours=1), @@ -1769,7 +1769,7 @@ class ActivateTest(ZulipTestCase): hamlet = self.example_user("hamlet") to_user_ids = [hamlet.id, iago.id] send_future_email( - "zerver/emails/followup_day2", + "zerver/emails/onboarding_zulip_topics", iago.realm, to_user_ids=to_user_ids, delay=datetime.timedelta(hours=1), @@ -1792,7 +1792,7 @@ class ActivateTest(ZulipTestCase): [ f"WARNING:zulip.send_email:ScheduledEmail {email_id} at {scheduled_at} " "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': {}}" ], )