Примеры приведены для платформы edX версии Maple.
Для отправки письма мы хотим использовать готовый шаблон.
Шаблоны писем размазаны по всему проекту, что, конечно, очень удобно. Тем не менее, их можно найти:
cd edx-platform
find . -type d -name email
Вот несколько примеров:
- ./common/templates/student/edx_ace/accountactivation/email
- ./lms/templates/instructor/edx_ace/allowedenroll/email
- ./openedx/core/djangoapps/user_authn/templates/user_authn/edx_ace/passwordreset/email
Остановимся на первом из них - accountactivation - и рассмотрим как его отправить. Дальнейшие действия мы будем выполнять в интерактивной оболочке django:
# cd edx-platform
./manage.py lms shell
Нужно импортировать класс, соответствующий письму активации. Его определение располагается в файле message_types.py
:
from common.djangoapps.student.message_types import AccountActivation
Здесь хочется обратить внимание на два момента, которые позволят лучше понять, что происходит:
- Определение класса "живёт" в том же приложении, что и шаблон письма. В данном случае, в приложении
student
.
- Имя поддиректории
accountactivation
совпадает с именем класса в нижнем регистре.
Итак, мы разобрались с шаблоном письма. Далее нам потребуется адресат:
from django.contrib.auth.models import User
from edx_ace.recipient import Recipient
user = User.objects.get(email='test@example.com')
recipient = Recipient(user, user.email)
Теперь мы можем подготовить контекст. Контекст представляет собой словарь данных (dict), значения из которого подставляются в шаблон, а на выходе мы получаем готовый текст.
Описать контекст можно полностью вручную или воспользоваться вспомогательной функцией, при наличии. Для письма регистрации такая функция есть и мы ей воспользуемся.
На вход функция принимает два объекта: User
и Registration
. Пользователя мы уже получили ранее, второй объект получить просто:
registration = user.registration
А теперь подробней рассмотрим определение функции:
def generate_activation_email_context(user, registration):
"""
Constructs a dictionary for use in activation email contexts
Arguments:
user (User): Currently logged-in user
registration (Registration): Registration object for the currently logged-in user
"""
context = get_base_template_context(None)
context.update({
'name': user.profile.name,
'key': registration.activation_key,
'lms_url': configuration_helpers.get_value('LMS_ROOT_URL', settings.LMS_ROOT_URL),
'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME),
'contact_mailing_address': configuration_helpers.get_value(
'contact_mailing_address',
settings.CONTACT_MAILING_ADDRESS
),
'support_url': configuration_helpers.get_value(
'ACTIVATION_EMAIL_SUPPORT_LINK', settings.ACTIVATION_EMAIL_SUPPORT_LINK
) or settings.SUPPORT_SITE_LINK,
'support_email': configuration_helpers.get_value('CONTACT_EMAIL', settings.CONTACT_EMAIL),
'site_configuration_values': configuration_helpers.get_current_site_configuration_values(),
})
return context
Невооруженным взглядом можно заметить, что контекст зависит от конфигурации сайта, а та в свою очередь зависит от домена, на который поступил HTTP-запрос.
— Запрос? Какой запрос?
Верно подмечено! Мы работаем в интерактивной оболочке, поэтому запрос придётся эмулировать:
from openedx.core.lib.celery.task_utils import emulate_http_request
from django.contrib.sites.models import Site
from edx_django_utils.cache import RequestCache
RequestCache(namespace="site_config").clear()
site = Site.objects.get(domain='education.example.com')
with emulate_http_request(site=site, user=user):
context = generate_activation_email_context(user, registration)
...
Здесь можно заметить вызов метода clear()
у объекта RequestCache
, что связано с особенностями реализации. Если этого не сделать, то конфигурация сайта не применится.
Остаётся лишь сформировать и отправить письмо внутри того же блока with ...
для работы встроенной аналитики:
...
from edx_ace import ace
msg = AccountActivation().personalize(
recipient=recipient,
language='RU',
user_context=context,
)
ace.send(msg)
Всё, можно ловить письмо!
Ну и напоследок соберём весь код вместе:
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from edx_ace import ace
from edx_ace.recipient import Recipient
from edx_django_utils.cache import RequestCache
from common.djangoapps.student.email_helpers import generate_activation_email_context
from common.djangoapps.student.message_types import AccountActivation
from openedx.core.lib.celery.task_utils import emulate_http_request
user = User.objects.get(email='test@example.com')
recipient = Recipient(user, user.email)
registration = user.registration
RequestCache(namespace="site_config").clear()
site = Site.objects.get(domain='education.example.com')
with emulate_http_request(site=site, user=user):
context = generate_activation_email_context(user, registration)
msg = AccountActivation().personalize(
recipient=recipient,
language='RU',
user_context=context,
)
ace.send(msg)