forked from mozilla/pontoon
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ability to send notifications via email (mozilla#3456)
This PR implements all the changes to the user settings as per the spec: https://github.com/mozilla/pontoon/blob/main/specs/0120-transactional-emails.md#settings-changes It also introduces a management command to send daily or weekly email notifications. Related changes: * Add PNG logo, needed for the display in emails (SVG is not supported in Gmail) * Store notification categories in the data model - Use these categories to determine to which category the user is subscribed - Add data migration to store categories for old notifications Other changes, not directly related to the PR: * Reorder sections in the Settings page by moving Email and Notifications sections next to another. * The settings.html file has been reformatted. Please hide whitespace in the diff for easier overview of changes. * Minor changes to the check-box widget markup and styling. * Minor changes to the success messages when toggling checkboxes. * Explicity set from: email address everywhere we send emails.
- Loading branch information
Showing
32 changed files
with
1,016 additions
and
177 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
pontoon/base/migrations/0068_userprofile_notification_emails.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# Generated by Django 4.2.16 on 2024-11-21 16:26 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
dependencies = [ | ||
("base", "0067_remove_userprofile_community_builder_level_and_more"), | ||
] | ||
|
||
operations = [ | ||
migrations.AddField( | ||
model_name="userprofile", | ||
name="comment_notifications_email", | ||
field=models.BooleanField(default=False), | ||
), | ||
migrations.AddField( | ||
model_name="userprofile", | ||
name="monthly_activity_summary", | ||
field=models.BooleanField(default=False), | ||
), | ||
migrations.AddField( | ||
model_name="userprofile", | ||
name="new_contributor_notifications_email", | ||
field=models.BooleanField(default=False), | ||
), | ||
migrations.AddField( | ||
model_name="userprofile", | ||
name="new_string_notifications_email", | ||
field=models.BooleanField(default=False), | ||
), | ||
migrations.AddField( | ||
model_name="userprofile", | ||
name="notification_email_frequency", | ||
field=models.CharField( | ||
choices=[("Daily", "Daily"), ("Weekly", "Weekly")], | ||
default="Weekly", | ||
max_length=10, | ||
), | ||
), | ||
migrations.AddField( | ||
model_name="userprofile", | ||
name="project_deadline_notifications_email", | ||
field=models.BooleanField(default=False), | ||
), | ||
migrations.AddField( | ||
model_name="userprofile", | ||
name="review_notifications_email", | ||
field=models.BooleanField(default=False), | ||
), | ||
migrations.AddField( | ||
model_name="userprofile", | ||
name="unreviewed_suggestion_notifications_email", | ||
field=models.BooleanField(default=False), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import logging | ||
import re | ||
|
||
from django.db import migrations | ||
|
||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
def get_category(notification): | ||
verb = notification.verb | ||
desc = notification.description | ||
|
||
# New strings notifications | ||
if re.match(r"updated with \d+ new string", verb): | ||
return "new_string" | ||
|
||
# Project target dates notifications | ||
if re.match(r"due in \d+ days", verb): | ||
return "project_deadline" | ||
|
||
# Comments notifications | ||
if re.match(r"has (pinned|added) a comment in", verb): | ||
return "comment" | ||
|
||
# New suggestions ready for review notifications | ||
if verb == "": | ||
return "unreviewed_suggestion" | ||
|
||
if verb == "has reviewed suggestions": | ||
# Review actions on own suggestions notifications | ||
if desc.startswith("Your suggestions have been reviewed"): | ||
return "review" | ||
|
||
# New team contributors notifications | ||
if "has made their first contribution to" in desc: | ||
return "new_contributor" | ||
|
||
if verb == "has sent a message in" or verb == "has sent you a message": | ||
return "direct_message" | ||
|
||
return None | ||
|
||
|
||
def store_notification_categories(apps, schema_editor): | ||
Notification = apps.get_model("notifications", "Notification") | ||
notifications = Notification.objects.all() | ||
unchanged = [] | ||
|
||
for notification in notifications: | ||
category = get_category(notification) | ||
|
||
if category == "direct_message": | ||
notification.data["category"] = category | ||
elif category: | ||
notification.data = {"category": category} | ||
else: | ||
unchanged.append(notification) | ||
|
||
Notification.objects.bulk_update(notifications, ["data"], batch_size=2000) | ||
|
||
log.info(f"Notifications categorized: {len(notifications) - len(unchanged)}.") | ||
log.info(f"Notifications left unchanged: {len(unchanged)}.") | ||
|
||
|
||
class Migration(migrations.Migration): | ||
dependencies = [ | ||
("base", "0068_userprofile_notification_emails"), | ||
("notifications", "0009_alter_notification_options_and_more"), | ||
] | ||
|
||
operations = [ | ||
migrations.RunPython( | ||
code=store_notification_categories, | ||
reverse_code=migrations.RunPython.noop, | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.