devilry_message — Devilry message framework

The devilry_message module handles the sending of emails.

Datamodel API

class devilry.devilry_message.models.base.Message(*args, **kwargs)

Bases: django.db.models.base.Model

The Message-class handles preparing and sending of different messages in the Devilry-system.

This model contains metadata about a message sent to one or multiple users, what type of message it is, the overall status of the message and creates recipients for the email to be sent.

Notes

The actual subject and message-content is stored on each MessageReceiver with a foreignkey to this class. The reason for this being that we want to save the subject and content in the preferred language of the user.

created_datetime

When the message was created.

created_by

The user that created the message.

This field may be None as we need to support system message and other messages with no specific user.

STATUS_CHOICES = <ievv_opensource.utils.choices_with_meta.ChoicesWithMeta object>

Choices for status.

  • draft: The message is in the draft state. This means that it has not been queued for sending yet, and can still be changed.
  • preparing: The message is being prepared for sending. This means that a background task is creating MessageReceiver objects for the message.
  • sending: A background task is sending the message.
  • error: Something went wrong. Details in status_data.
  • sent: The message has been sent without any errors.
status

The “send”-status of a message.

See BaseMessage.STATUS_CHOICES.

status_data

Extra data for the status as JSON.

metadata

Extra metadata for the message receiver as JSON. This can be anything.

CONTEXT_TYPE_CHOICES = <ievv_opensource.utils.choices_with_meta.ChoicesWithMeta object>

The available context types of the message.

The purpose of the context type is to provide better filtering options.

  • other: Unspecified type.
  • comment: Message regarding new comment/delivery.
  • deadline_moved: Message regarding a moved deadline.
  • feedback: Message regarding feedback/grading.
  • feedback_updated: Message regarding an updated grade/result.
context_type

The context type of the message. See CONTEXT_TYPE_CHOICES for more info.

message_type

ArrayField with the types for this message.

Examples: - ['email']: Send as email only.

virtual_message_receivers

Store data needed to create MessageReceiver-objects.

Each subclass defines how the dataformat of this field should be. Override Message.prepare_message_receivers to create message receivers from this field.

prepare_message_receivers(subject_generator, template_name, template_context)

Prepare MessageReceiver objects for create_message_receivers(). By _prepare_, we mean to make the MessageReceiver objects, but not save them to the database.

Saving is handled with a bulk create in create_message_receivers().

Must return a list of MessageReceiver objects, or a generator that yields lists of MessageReceiver objects.

validate_virtual_message_receivers()

This method can be overriden to add custom validation for BaseMessage.virtual_message_receivers in subclasses.

Does nothing by default.

create_message_receivers(**kwargs)

Creates message receivers from list returned from BaseMessage.prepare_message_receivers()

prepare_and_send(subject_generator, template_name, template_context)

Prepare and send message to message receivers.

  1. Create MessageReceiver`s for this message. Set status to `preparing.
  2. Send message to MessageReceover`s for this message. Set status to `sending.
  3. Set status to sent.
Raises:
  • ValueError if the status of a the message is not draft. A message that
  • is not a draft can not be resent via this method.
clean_message_type()

Sets email as default message type if empty or None.

clean()

Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.

exception DoesNotExist

Bases: django.core.exceptions.ObjectDoesNotExist

exception MultipleObjectsReturned

Bases: django.core.exceptions.MultipleObjectsReturned

class devilry.devilry_message.models.base.MessageReceiverQuerySet(model=None, query=None, using=None, hints=None)

Bases: django.db.models.query.QuerySet

create_receiver(user, message, message_type, subject_generator, template_name, template_context)

Create a message receiver and generate the email content and subject according to the preferred language of the user and return the MessageReceiver-instance. This method cleans the receiver object, but DOES NOT SAVE IT.

Parameters:
  • user – A devilry.devilry_account.models.User-instance.
  • message – A Message-instance this receiver belongs to.
  • message_type – The type of message (email, sms, …).
  • subject_generator – A subclass of devilry.devilry_message.utils.subject_generator.SubjectTextGenerator
  • template_name – Template to render content with (a path).
  • template_context – Context data for template.
Returns:

Unsaved instance.

Return type:

MessageRecveiver

filter_old_receivers(datetime_obj)

Filter all MessageReceivers created before the given datetime_obj-argument.

class devilry.devilry_message.models.base.MessageReceiver(*args, **kwargs)

Bases: django.db.models.base.Model

This class represents a single message to a single user.

Contains data about the specific message for a user:
  • ForeignKey to a user.
  • The status of the sending.
  • How many time the message has been successfully and unsuccessfully sent to the user.
  • The subject.
  • The content as both html and plaintext.
  • When the message was successfully sent.

The subject and message-content is stored in the users preferred language when the first message was created.

created_datetime

When the message receiver was created.

STATUS_CHOICES = <ievv_opensource.utils.choices_with_meta.ChoicesWithMeta object>

Choices for the MessageReceiver.status field.

  • not_sent: The MessageReceiver has just been created, but not sent yet.
  • error: An error occurred when trying to send the message. The status is set to failed if the sending_failed_count is greater than the resend limit defined by the DEVILRY_MESSAGE_RESEND_LIMIT-setting. Error-details and traceback is stored in status_data.
  • failed: The message failed, same as error, but the status is set to failed if the sending_failed_count is less than or equal to the resend limit defined by the DEVILRY_MESSAGE_RESEND_LIMIT-setting. Error-details and traceback is stored in status_data.
  • sent: The message was sent to a backend (mailserver, SMS-provider etc.) without any errors.
status

The status of the message. Must be one of the choices defined in STATUS_CHOICES.

status_data

Extra data for the status as JSON. Typically used to save responses from the APIs used to send the message, especially error responses.

metadata

Extra metadata for the message receiver as JSON. This can be anything.

subject

The subject of the message.

Only used for emails.

message_content_plain

Message content plain text.

If MessageReceiver.message_content_html is set, the HTML content is converted to plaint text and saved on this field.

message_content_html

Message content HTML.

Optional, but normally used when sending an email.

message

The BaseMessage this message receiver belongs too.

message_type

The message type. Will always be one of the message types in the BaseMessage.message_types list of the message.

send_to

The receivers email-address. A user can have multiple email-addresses, this is the actual address for the user the mail was sent/will be sent to.

user

The User to send this to. Currently we only send to registered users, so this field is required.

sent_datetime

The datetime the message was successfully sent to the user.

sending_failed_count

Number of failed attempts.

sending_success_count

Number of successful attempts.

send()

Simply sends a message to this receiver. This method can also be used to resend an email.

clean_message_content_fields()

If BaseMessage.message_content_html has content and BaseMessage.message_content_plain has not, convert the HTML-content to plaintext and set it on the message_content_plain-field.

clean_message_type()

Sets email as default message type if empty or None.

clean()

Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.

exception DoesNotExist

Bases: django.core.exceptions.ObjectDoesNotExist

exception MultipleObjectsReturned

Bases: django.core.exceptions.MultipleObjectsReturned