General A/B testing.
[wolnelektury.git] / src / messaging / models.py
1 from django.conf import settings
2 from django.core.mail import send_mail
3 from django.db import models
4 from django.template import Template, Context
5 from django.utils.translation import ugettext_lazy as _
6 from sentry_sdk import capture_exception
7 from .states import states
8
9
10 class EmailTemplate(models.Model):
11     state = models.CharField(_('state'), max_length=128, choices=[(s.slug, s.name) for s in states], help_text='?')
12     subject = models.CharField(_('subject'), max_length=1024)
13     body = models.TextField(_('body'))
14     days = models.SmallIntegerField(_('days'), null=True, blank=True)
15     hour = models.IntegerField(_('hour'), null=True, blank=True)
16
17     class Meta:
18         verbose_name = _('email template')
19         verbose_name_plural = _('email templates')
20
21     def __str__(self):
22         return '%s (%+d)' % (self.get_state_display(), self.days)
23         return self.subject
24
25     def run(self, time=None, verbose=False, dry_run=False):
26         state = self.get_state()
27         recipients = state(time=time, offset=self.days).get_recipients()
28         hash_values = set(recipient.hash_value for recipient in recipients)
29         sent = set(EmailSent.objects.filter(
30                 template=self, hash_value__in=hash_values
31             ).values_list('hash_value', flat=True))
32         for recipient in recipients:
33             if recipient.hash_value in sent:
34                 continue
35             self.send(recipient, verbose=verbose, dry_run=dry_run)
36
37     def get_state(self):
38         for s in states:
39             if s.slug == self.state:
40                 return s
41         raise ValueError('Unknown state', s.state)
42
43     def send(self, recipient, verbose=False, dry_run=False):
44         subject = Template(self.subject).render(Context(recipient.context))
45         body = Template(self.body).render(Context(recipient.context))
46         if verbose:
47             print(recipient.email, subject)
48         if not dry_run:
49             try:
50                 send_mail(subject, body, settings.CONTACT_EMAIL, [recipient.email], fail_silently=False)
51             except:
52                 capture_exception()
53             else:
54                 self.emailsent_set.create(
55                     hash_value=recipient.hash_value,
56                     email=recipient.email,
57                     subject=subject,
58                     body=body,
59                 )
60
61
62
63 class EmailSent(models.Model):
64     template = models.ForeignKey(EmailTemplate, models.CASCADE)
65     hash_value = models.CharField(max_length=1024)
66     timestamp = models.DateTimeField(auto_now_add=True)
67     email = models.CharField(_('e-mail'), max_length=1024)
68     subject = models.CharField(_('subject'), max_length=1024)
69     body = models.TextField(_('body'))
70
71     class Meta:
72         verbose_name = _('email sent')
73         verbose_name_plural = _('emails sent')
74         ordering = ('-timestamp',)
75
76     def __str__(self):
77         return '%s %s' % (self.email, self.timestamp)