-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: added edx-ace template and message type for email notifications #34315
Changes from all commits
2104fad
5f74fe1
366ecd5
a6a938f
ac0a7d6
a2c9c26
c715425
e680d1b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5387,10 +5387,13 @@ def _make_locale_paths(settings): # pylint: disable=missing-function-docstring | |
SUBSCRIPTIONS_TRIAL_LENGTH = 7 | ||
SUBSCRIPTIONS_SERVICE_WORKER_USERNAME = 'subscriptions_worker' | ||
|
||
############## NOTIFICATIONS EXPIRY ############## | ||
############## NOTIFICATIONS ############## | ||
NOTIFICATIONS_EXPIRY = 60 | ||
EXPIRED_NOTIFICATIONS_DELETE_BATCH_SIZE = 10000 | ||
NOTIFICATION_CREATION_BATCH_SIZE = 99 | ||
NOTIFICATIONS_DEFAULT_FROM_EMAIL = "[email protected]" | ||
NOTIFICATION_TYPE_ICONS = {} | ||
DEFAULT_NOTIFICATION_ICON_URL = "" | ||
|
||
############################ AI_TRANSLATIONS ################################## | ||
AI_TRANSLATIONS_API_URL = 'http://localhost:18760/api/v1' | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
""" | ||
Email notifications MessageType | ||
""" | ||
from django.conf import settings | ||
from edx_ace.message import MessageType | ||
|
||
|
||
class EmailNotificationMessageType(MessageType): | ||
""" | ||
Edx-ace MessageType for Email Notifications | ||
""" | ||
|
||
NAME = "notifications" | ||
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
self.options['transactional'] = True | ||
self.options['from_address'] = settings.NOTIFICATIONS_DEFAULT_FROM_EMAIL |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
""" | ||
Notification Icons | ||
""" | ||
from django.conf import settings | ||
|
||
|
||
class NotificationTypeIcons: | ||
""" | ||
Notification Mapping with icons | ||
""" | ||
CHECK_CIRCLE_GREEN = "CHECK_CIRCLE_GREEN" | ||
HELP_OUTLINE = "HELP_OUTLINE" | ||
NEWSPAPER = "NEWSPAPER" | ||
POST_OUTLINE = "POST_OUTLINE" | ||
QUESTION_ANSWER_OUTLINE = "QUESTION_ANSWER_OUTLINE" | ||
REPORT_RED = "REPORT_RED" | ||
VERIFIED = "VERIFIED" | ||
|
||
@classmethod | ||
def get_icon_name_for_notification_type(cls, notification_type, default="POST_OUTLINE"): | ||
""" | ||
Returns icon name for notification type | ||
""" | ||
notification_type_dict = { | ||
"new_comment_on_response": cls.QUESTION_ANSWER_OUTLINE, | ||
"new_comment": cls.QUESTION_ANSWER_OUTLINE, | ||
"new_response": cls.QUESTION_ANSWER_OUTLINE, | ||
"new_discussion_post": cls.POST_OUTLINE, | ||
"new_question_post": cls.HELP_OUTLINE, | ||
"response_on_followed_post": cls.QUESTION_ANSWER_OUTLINE, | ||
"comment_on_followed_post": cls.QUESTION_ANSWER_OUTLINE, | ||
"content_reported": cls.REPORT_RED, | ||
"response_endorsed_on_thread": cls.VERIFIED, | ||
"response_endorsed": cls.CHECK_CIRCLE_GREEN, | ||
"course_update": cls.NEWSPAPER, | ||
} | ||
return notification_type_dict.get(notification_type, default) | ||
|
||
@classmethod | ||
def get_icon_url_for_notification_type(cls, notification_type): | ||
""" | ||
Returns icon url for notification type | ||
""" | ||
icon_name = cls.get_icon_name_for_notification_type(notification_type) | ||
return settings.NOTIFICATION_TYPE_ICONS.get(icon_name, settings.DEFAULT_NOTIFICATION_ICON_URL) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
""" | ||
Email Notifications Utils | ||
""" | ||
from django.conf import settings | ||
from lms.djangoapps.branding.api import get_logo_url_for_email | ||
from .notification_icons import NotificationTypeIcons | ||
|
||
|
||
def create_datetime_string(datetime_instance): | ||
return datetime_instance.strftime('%A, %b %d') | ||
|
||
|
||
def get_icon_url_for_notification_type(notification_type): | ||
""" | ||
Returns icon url for notification type | ||
""" | ||
return NotificationTypeIcons.get_icon_url_for_notification_type(notification_type) | ||
|
||
|
||
def create_email_template_context(): | ||
""" | ||
Creates email context for header and footer | ||
""" | ||
social_media_urls = settings.SOCIAL_MEDIA_FOOTER_ACE_URLS | ||
social_media_icons = settings.SOCIAL_MEDIA_LOGO_URLS | ||
social_media_info = { | ||
social_platform: { | ||
'url': social_media_urls[social_platform], | ||
'icon': social_media_icons[social_platform] | ||
} | ||
for social_platform in social_media_urls.keys() | ||
if social_media_icons.get(social_platform) | ||
} | ||
return { | ||
"platform_name": settings.PLATFORM_NAME, | ||
"mailing_address": settings.CONTACT_MAILING_ADDRESS, | ||
"logo_url": get_logo_url_for_email(), | ||
"social_media": social_media_info, | ||
"notification_settings_url": f"{settings.ACCOUNT_MICROFRONTEND_URL}/notifications", | ||
} | ||
|
||
|
||
def create_email_digest_content(start_date, end_date=None, digest_frequency="Daily", | ||
notifications_count=0, updates_count=0, email_content=None): | ||
""" | ||
Creates email context based on content | ||
start_date: datetime instance | ||
end_date: datetime instance | ||
Comment on lines
+45
to
+48
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please update DocString with some more details, including the optional params There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will be updated on integration. |
||
""" | ||
context = create_email_template_context() | ||
start_date_str = create_datetime_string(start_date) | ||
end_date_str = create_datetime_string(end_date if end_date else start_date) | ||
Comment on lines
+51
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are these going to be UTC? What time will the user receive these digest emails? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The task will run at 00:00 UTC but timezone is not needed for creating string. Format for string is |
||
context.update({ | ||
"start_date": start_date_str, | ||
"end_date": end_date_str, | ||
"digest_frequency": digest_frequency, | ||
"updates": [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we rename this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will be updated when it will be integrated to send email. There are some ambiguities where it is being used. |
||
{"count": updates_count, "type": "Updates"}, | ||
{"count": notifications_count, "type": "Notifications"} | ||
], | ||
"email_content": email_content if email_content else [], | ||
"get_icon_url_for_notification_type": get_icon_url_for_notification_type, | ||
}) | ||
return context |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
{% for update in email_content %} | ||
<h3 style="font-size: 1.375rem; font-weight:700; line-height:28px; margin: 0.75rem 0 0;"> | ||
{{ update.title }} | ||
</h3> | ||
{% if update.help_text %} | ||
<p style="margin: 0; height: 1.5rem; font-weight: 400; font-size: 14px; line-height: 24px"> | ||
<span style="float:left; color:#707070;"> | ||
{{ update.help_text }} | ||
</span> | ||
{% if update.help_text_url %} | ||
<span style="float:right; margin-right: 0.25rem"> | ||
<a href="{{help_text_url}}" style="text-decoration: none; color: #00688D"> | ||
View all | ||
</a> | ||
</span> | ||
{% endif %} | ||
</p> | ||
{% endif %} | ||
<p style="height: 1rem; margin: 0;" /> | ||
<p style="margin: 0;"> | ||
<table style="background-color: #FBFAF9; border-radius: 8px; padding: 0.5rem 0" width="100%"> | ||
<tbody> | ||
{% for content in update.content %} | ||
<tr> | ||
<td align="left" valign="top" style="padding: 1rem 0 1rem 1rem"> | ||
<img | ||
src="https://edx-notifications-static.edx.org/icons/newspaper.png" | ||
style="max-height: 28px; max-width: 28px; margin: 0.75rem 1rem 0.75rem 0" | ||
/> | ||
</td> | ||
<td width="100%" align="left" valign="top" style=" padding: 1rem 1rem 1rem 0.5rem"> | ||
<p style="font-size: 0.875rem; font-weight:400; line-height:24px; color:#454545; margin: 0;"> | ||
{{ content.title }} | ||
</p> | ||
<p style="height: 0.5rem; margin: 0"></p> | ||
<p style="color:#707070; margin: 0"> | ||
<span style="float: left"> | ||
<span>{{ content.course_name }}</span> | ||
<span style="padding: 0 0.375rem">·</span> | ||
<span>{{ content.time_ago }}</span> | ||
</span> | ||
<span style="float: right"> | ||
<a href="{{content.url}}" style="text-decoration: none; color: #00688D"> | ||
View | ||
</a> | ||
</span> | ||
</p> | ||
</td> | ||
</tr> | ||
{% endfor %} | ||
</tbody> | ||
</table> | ||
</p> | ||
<p style="height: 0.75rem; margin: 0;" /> | ||
{% endfor %} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<table cellpadding="0" cellspacing="0" style="color:black; font-weight:400; font-size:0.75rem;line-height:20px" width="100%"> | ||
<tbody> | ||
<tr> | ||
<td> | ||
<table width="100%"> | ||
<tbody> | ||
<tr> | ||
<td width="25%" align="left" style="padding: 0"> | ||
<img src="{{ logo_url }}" style="width: auto;" height="24" alt="Logo"/></a> | ||
</td> | ||
<td width="75%" align="right" style="padding: 0"> | ||
<table> | ||
<tbody> | ||
<tr> | ||
{% for social_name, social_data in social_media.items %} | ||
<td style="padding: 0"> | ||
<a href="{{social_data.url}}"> | ||
<img src="{{social_data.icon}}" style="max-height: 24px; max-width: 24px; margin-left: 0.6rem" alt="{{social_name}}" /> | ||
</a> | ||
</td> | ||
{% endfor %} | ||
</tr> | ||
</tbody> | ||
</table> | ||
</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
</td> | ||
</tr> | ||
<tr> | ||
<td> | ||
<p style="margin: 1.5rem 0 0 0;"> | ||
You are receiving this email because you have subscribed to email digest | ||
</p> | ||
<p style="margin: 0.625rem 0"> | ||
<a href="{{notification_settings_url}}" rel="noopener noreferrer" target="_blank" style="color: black"> | ||
Notification Settings | ||
</a> | ||
</p> | ||
<p> | ||
© {% now "Y" %} {{ platform_name }}. All Rights Reserved <br/> | ||
{{ mailing_address }} | ||
</p> | ||
</td> | ||
</tr> | ||
</tbody> | ||
</table> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<table | ||
border="0" | ||
cellpadding="0" | ||
cellspacing="0" | ||
style="background: #00262b; color: white; width: 100%; padding: 1.5rem" | ||
> | ||
<tbody> | ||
<tr align="center"> | ||
<td> | ||
<img src="{{ logo_url }}" style="width: 64px" height="auto" alt="logo_url" /> | ||
</td> | ||
</tr> | ||
<tr style="height: 20px"></tr> | ||
<tr align="center"> | ||
<td style="font-family: Inter; font-size: 32px; font-style: normal; font-weight: 700; line-height: 36px"> | ||
{{ digest_frequency }} email digest | ||
</td> | ||
</tr> | ||
<tr style="height: 10px"></tr> | ||
<tr align="center"> | ||
<td | ||
style=" | ||
color: #bfc9ca; | ||
font-family: Inter; | ||
font-size: 14px; | ||
font-style: normal; | ||
font-weight: 400; | ||
line-height: 28px; | ||
" | ||
> | ||
{{ start_date }} {% if digest_frequency == "Weekly" %} - {{ end_date }} {% endif %} | ||
</td> | ||
</tr> | ||
<tr style="height: 24px"></tr> | ||
<tr align="center"> | ||
<td> | ||
<table width="100%" border="0" cellpadding="0"> | ||
<tbody> | ||
<tr> | ||
{% for update in updates %} | ||
<td width="50%"> | ||
<p style=" | ||
{% if not forloop.last %}padding-right: 0.5rem{% endif %} | ||
{% if not forloop.first %}padding-left: 0.5rem{% endif %}" | ||
> | ||
<table | ||
width="100%" | ||
cellpadding="0" | ||
cellspacing="0" | ||
style="background: #1b3b40; color: white; border-radius: 8px; | ||
padding: 1.25rem 1rem;" | ||
> | ||
<tbody> | ||
<tr align="center"> | ||
<td style="font-weight: 700; font-size: 32px; line-height: 44px; padding: 0"> | ||
{{update.count}} | ||
</td> | ||
</tr> | ||
<tr align="center"> | ||
<td style="font-weight: 600; font-size: 0.875rem; line-height: 20px; padding: 0"> | ||
{{update.type}} | ||
</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
</p> | ||
</td> | ||
{% endfor %} | ||
</tr> | ||
</tbody> | ||
</table> | ||
</td> | ||
</tr> | ||
</tbody> | ||
</table> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<%page expression_filter="h"/> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<div style="margin:0; padding:0; min-width: 100%; background-color: background-color:#C9C9C9"> | ||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="100%" style="line-height:1.5; max-width:600px; font-family:Inter"> | ||
<tbody style="background-color:#f5f5f5"> | ||
<tr> | ||
<td> | ||
{% include 'notifications/digest_header.html' %} | ||
</td> | ||
</tr> | ||
<tr> | ||
<td style="padding:0.75rem 1.5rem; background-color:white"> | ||
{% include 'notifications/digest_content.html' %} | ||
</td> | ||
</tr> | ||
<tr> | ||
<td style="padding: 1.5rem; background-color: #F2F0EF"> | ||
{% include 'notifications/digest_footer.html' %} | ||
</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
|
||
</div> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{{ platform_name }} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<%page expression_filter="h"/> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{{ digest_frequency }} Notifications Digest for {% if digest_frequency == "Weekly" %}the Week of {% endif %}{{ start_date }} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens here for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For daily digest: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need this method when we already have the get icon method in
NotificationTypeIcons
classThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can remove it. I thought of making all methods available in
utils.py
.