django-informativo / informativo / models.py

import smtplib

from datetime import datetime

from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import ugettext_lazy as _

from informativo.utils import send_mass_mail


NEWSLETTER_STATUS = (
    ('canceled', _('canceled')),
    ('waiting', _('waiting sending')),
    ('sending', _('sending')),
    ('sent', _('sent')),
)

CONTACT_MAILING_STATUS = (
    ('canceled', _('canceled')),
    ('sending', _('sending')),
    ('sent', _('sent')),
    ('failed', _('failed')),
)


def get_default_mailinglist():
    ids = MailingList.objects.values_list('id', flat=True)
    if len(ids) == 1:
        return ids
    return []

class Contact(models.Model):
    first_name = models.CharField(_('first name'), max_length=64, blank=True)
    last_name = models.CharField(_('last name'), max_length=64, blank=True)
    email = models.EmailField(_('e-mail'), unique=True)
    mailing_lists = models.ManyToManyField(
        'informativo.MailingList',
        verbose_name=_('mailing lists'),
        related_name='subscribers',
        default=get_default_mailinglist
    )

    class Meta:
        verbose_name = _('contact')
        verbose_name_plural = _('contacts')
        ordering = ('-id',)

    def __unicode__(self):
        if self.first_name and self.last_name:
            return u'%s %s <%s>' % (self.first_name, self.last_name, self.email)
        return u'%s' % self.email


class MailingList(models.Model):
    name = models.CharField(_('name'), max_length=64)
    description = models.TextField(_('description'), blank=True)

    class Meta:
        verbose_name = _('mailing list')
        verbose_name_plural = _('mailing lists')
        ordering = ('-id',)

    def __unicode__(self):
        return unicode(self.name)


class Newsletter(models.Model):
    title = models.CharField(
        _('title'),
        max_length=128,
        help_text=_("Used on the e-mail's subject")
    )
    html_content = models.TextField(_('HTML content'), blank=True)
    text_content = models.TextField(_('text content'), blank=True)
    mailing_list = models.ForeignKey(MailingList, verbose_name=_('mailing list'))
    sending_date = models.DateTimeField(
        _('sending date'),
        default=datetime.now,
    )
    status = models.CharField(
        _('status'),
        max_length=16,
        choices=NEWSLETTER_STATUS,
        default='waiting'
    )

    class Meta:
        verbose_name = _('newsletter')
        verbose_name_plural = _('newsletters')
        ordering = ('-id',)

    def __unicode__(self):
        return unicode(self.title)

    def clean(self):
        if not self.html_content and not self.text_content:
            raise ValidationError(_('You must provide a HTML or text content!'))
        # Set the pub_date for published items if it hasn't been set already.
        if self.status == 'published' and self.pub_date is None:
            self.pub_date = datetime.datetime.now()

    def save(self, *args, **kwargs):
        if not self.text_content and self.html_content:
            self.text_content = _(
                'This message contains an HTML formatted message but your '
                'e-mail client does not support the display of HTML.'
            )
        return super(Newsletter, self).save(*args, **kwargs)

    def send(self):
        subject = self.title
        text_content, html_content = self.text_content, self.html_content
        from_email = settings.DEFAULT_FROM_EMAIL

        self.status = 'sending'
        self.save()

        for recipient in self.mailing_list.subscribers.all():
            contact_status, created = ContactMailingStatus.objects.get_or_create(
                contact=recipient,
                newsletter=self,
                defaults={'status': 'sending'}
            )

            # Do not send the same newsletter to the same recipient twice
            if contact_status.status in ('canceled', 'sent'):
                continue

            # Send mail
            datatuple = ((subject, text_content, html_content, from_email, [recipient.email]),)
            try:
                send_mass_mail(datatuple)
                contact_status.status = 'sent'
                status = 'sent'
            except smtplib.SMTPException:
                contact_status.status = 'failed'
            contact_status.save()

        self.status = 'sent'
        self.save()


class ContactMailingStatus(models.Model):
    contact = models.ForeignKey(
        'informativo.Contact',
        verbose_name=_('contact')
    )
    newsletter = models.ForeignKey(
        'informativo.Newsletter',
        verbose_name=_('newsletter')
    )
    status = models.CharField(
        _('status'),
        max_length=16,
        choices=CONTACT_MAILING_STATUS
    )

    class Meta:
        verbose_name = _('contact mailing status')
        verbose_name_plural = _('contact mailing statuses')
        ordering = ('-id',)

    def __unicode__(self):
        status = self.get_status_display()
        return u'"%s" to %s %s' % (self.newsletter, self.contact, status)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.