mirror of https://github.com/zulip/zulip.git
scheduled-mails: Migrate existing scheduled emails to new templates.
Migrates existing ScheduledEmails for onboarding emails that have either "zerver/emails/followup_day1" or "zerver/emails/followup_day2" as the email template prefix to instead use the new template prefixes "zerver/emails/account_registered" and "zerver/emails/zulip_onboarding_topics".
This commit is contained in:
parent
438bcc1585
commit
5d5a578d6c
|
@ -0,0 +1,95 @@
|
|||
# Generated by Django 4.2.2 on 2023-07-11 10:45
|
||||
|
||||
from django.db import migrations
|
||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
from django.db.migrations.state import StateApps
|
||||
from django.db.models import F, Func, JSONField, TextField, Value
|
||||
from django.db.models.functions import Cast
|
||||
|
||||
# ScheduledMessage.type for onboarding emails from zerver/models.py
|
||||
WELCOME = 1
|
||||
|
||||
|
||||
def update_for_followup_day_email_templates_rename(
|
||||
apps: StateApps, schema_editor: BaseDatabaseSchemaEditor
|
||||
) -> None:
|
||||
ScheduledEmail = apps.get_model("zerver", "ScheduledEmail")
|
||||
|
||||
account_registered_emails = ScheduledEmail.objects.annotate(
|
||||
as_jsonb=Cast("data", JSONField())
|
||||
).filter(type=WELCOME, as_jsonb__template_prefix="zerver/emails/followup_day1")
|
||||
account_registered_emails.update(
|
||||
data=Cast(
|
||||
Func(
|
||||
F("as_jsonb"),
|
||||
Value(["template_prefix"]),
|
||||
Value("zerver/emails/account_registered", JSONField()),
|
||||
function="jsonb_set",
|
||||
),
|
||||
TextField(),
|
||||
)
|
||||
)
|
||||
|
||||
onboarding_zulip_topics_emails = ScheduledEmail.objects.annotate(
|
||||
as_jsonb=Cast("data", JSONField())
|
||||
).filter(type=WELCOME, as_jsonb__template_prefix="zerver/emails/followup_day2")
|
||||
onboarding_zulip_topics_emails.update(
|
||||
data=Cast(
|
||||
Func(
|
||||
F("as_jsonb"),
|
||||
Value(["template_prefix"]),
|
||||
Value("zerver/emails/onboarding_zulip_topics", JSONField()),
|
||||
function="jsonb_set",
|
||||
),
|
||||
TextField(),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def revert_followup_day_email_templates_rename(
|
||||
apps: StateApps, schema_editor: BaseDatabaseSchemaEditor
|
||||
) -> None:
|
||||
ScheduledEmail = apps.get_model("zerver", "ScheduledEmail")
|
||||
|
||||
rename_extradata_realmauditlog_extra_data_json = ScheduledEmail.objects.annotate(
|
||||
as_jsonb=Cast("data", JSONField())
|
||||
).filter(type=WELCOME, as_jsonb__template_prefix="zerver/emails/account_registered")
|
||||
rename_extradata_realmauditlog_extra_data_json.update(
|
||||
data=Cast(
|
||||
Func(
|
||||
F("as_jsonb"),
|
||||
Value(["template_prefix"]),
|
||||
Value("zerver/emails/followup_day1", JSONField()),
|
||||
function="jsonb_set",
|
||||
),
|
||||
TextField(),
|
||||
)
|
||||
)
|
||||
|
||||
rename_extradata_realmauditlog_extra_data_json = ScheduledEmail.objects.annotate(
|
||||
as_jsonb=Cast("data", JSONField())
|
||||
).filter(type=WELCOME, as_jsonb__template_prefix="zerver/emails/onboarding_zulip_topics")
|
||||
rename_extradata_realmauditlog_extra_data_json.update(
|
||||
data=Cast(
|
||||
Func(
|
||||
F("as_jsonb"),
|
||||
Value(["template_prefix"]),
|
||||
Value("zerver/emails/followup_day2", JSONField()),
|
||||
function="jsonb_set",
|
||||
),
|
||||
TextField(),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("zerver", "0467_rename_extradata_realmauditlog_extra_data_json"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
update_for_followup_day_email_templates_rename,
|
||||
reverse_code=revert_followup_day_email_templates_rename,
|
||||
),
|
||||
]
|
|
@ -4,7 +4,9 @@
|
|||
# You can also read
|
||||
# https://www.caktusgroup.com/blog/2016/02/02/writing-unit-tests-django-migrations/
|
||||
# to get a tutorial on the framework that inspired this feature.
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import orjson
|
||||
from django.db.migrations.state import StateApps
|
||||
|
||||
from zerver.lib.test_classes import MigrationsTestCase
|
||||
|
@ -26,56 +28,75 @@ from zerver.lib.test_helpers import use_db_models
|
|||
# been tested for a migration being merged.
|
||||
|
||||
|
||||
class RealmPlaygroundURLPrefix(MigrationsTestCase):
|
||||
migrate_from = "0462_realmplayground_url_template"
|
||||
migrate_to = "0463_backfill_realmplayground_url_template"
|
||||
class ScheduledEmailData(MigrationsTestCase):
|
||||
migrate_from = "0467_rename_extradata_realmauditlog_extra_data_json"
|
||||
migrate_to = "0468_rename_followup_day_email_templates"
|
||||
|
||||
@use_db_models
|
||||
def setUpBeforeMigration(self, apps: StateApps) -> None:
|
||||
iago = self.example_user("iago")
|
||||
RealmPlayground = apps.get_model("zerver", "RealmPlayground")
|
||||
ScheduledEmail = apps.get_model("zerver", "ScheduledEmail")
|
||||
send_date = datetime(2025, 1, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
|
||||
|
||||
urls = [
|
||||
"http://example.com/",
|
||||
"https://example.com/{",
|
||||
"https://example.com/{}",
|
||||
"https://example.com/{val}",
|
||||
"https://example.com/{code}",
|
||||
]
|
||||
self.realm_playground_ids = []
|
||||
|
||||
for index, url in enumerate(urls):
|
||||
self.realm_playground_ids.append(
|
||||
RealmPlayground.objects.create(
|
||||
realm=iago.realm,
|
||||
name=f"Playground {index}",
|
||||
pygments_language="Python",
|
||||
url_prefix=url,
|
||||
url_template=None,
|
||||
).id
|
||||
)
|
||||
self.realm_playground_ids.append(
|
||||
RealmPlayground.objects.create(
|
||||
realm=iago.realm,
|
||||
name="Existing Playground",
|
||||
pygments_language="Python",
|
||||
url_prefix="https://example.com",
|
||||
url_template="https://example.com/{code}",
|
||||
).id
|
||||
)
|
||||
|
||||
def test_converted_url_templates(self) -> None:
|
||||
RealmPlayground = self.apps.get_model("zerver", "RealmPlayground")
|
||||
|
||||
expected_urls = [
|
||||
"http://example.com/{code}",
|
||||
"https://example.com/%7B{code}",
|
||||
"https://example.com/%7B%7D{code}",
|
||||
"https://example.com/%7Bval%7D{code}",
|
||||
"https://example.com/%7Bcode%7D{code}",
|
||||
"https://example.com/{code}",
|
||||
templates = [
|
||||
["zerver/emails/followup_day1", "a", True, 10],
|
||||
["zerver/emails/followup_day2", "b", False, 20],
|
||||
["zerver/emails/onboarding_zulip_guide", "c", True, 30],
|
||||
]
|
||||
|
||||
for realm_playground_id, expected_url in zip(self.realm_playground_ids, expected_urls):
|
||||
realm_playground = RealmPlayground.objects.get(id=realm_playground_id)
|
||||
self.assertEqual(realm_playground.url_template, expected_url)
|
||||
for template in templates:
|
||||
email_fields = {
|
||||
"template_prefix": template[0],
|
||||
"string_context": template[1],
|
||||
"boolean_context": template[2],
|
||||
"integer_context": template[3],
|
||||
}
|
||||
|
||||
email = ScheduledEmail.objects.create(
|
||||
type=1,
|
||||
realm=iago.realm,
|
||||
scheduled_timestamp=send_date,
|
||||
data=orjson.dumps(email_fields).decode(),
|
||||
)
|
||||
email.users.add(iago.id)
|
||||
|
||||
def test_updated_email_templates(self) -> None:
|
||||
ScheduledEmail = self.apps.get_model("zerver", "ScheduledEmail")
|
||||
send_date = datetime(2025, 1, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
|
||||
|
||||
old_templates = [
|
||||
"zerver/emails/followup_day1",
|
||||
"zerver/emails/followup_day2",
|
||||
]
|
||||
|
||||
current_templates = [
|
||||
"zerver/emails/account_registered",
|
||||
"zerver/emails/onboarding_zulip_guide",
|
||||
"zerver/emails/onboarding_zulip_topics",
|
||||
]
|
||||
|
||||
email_data = [
|
||||
["zerver/emails/account_registered", "a", True, 10],
|
||||
["zerver/emails/onboarding_zulip_topics", "b", False, 20],
|
||||
["zerver/emails/onboarding_zulip_guide", "c", True, 30],
|
||||
]
|
||||
|
||||
scheduled_emails = ScheduledEmail.objects.all()
|
||||
self.assert_length(scheduled_emails, 3)
|
||||
|
||||
checked_emails = []
|
||||
for email in scheduled_emails:
|
||||
self.assertEqual(email.type, 1)
|
||||
self.assertEqual(email.scheduled_timestamp, send_date)
|
||||
|
||||
updated_data = orjson.loads(email.data)
|
||||
template_prefix = updated_data["template_prefix"]
|
||||
self.assertFalse(template_prefix in old_templates)
|
||||
for data in email_data:
|
||||
if template_prefix == data[0]:
|
||||
self.assertEqual(updated_data["string_context"], data[1])
|
||||
self.assertEqual(updated_data["boolean_context"], data[2])
|
||||
self.assertEqual(updated_data["integer_context"], data[3])
|
||||
checked_emails.append(template_prefix)
|
||||
|
||||
self.assertEqual(current_templates, sorted(checked_emails))
|
||||
|
|
Loading…
Reference in New Issue