]> git.0d.be Git - django-panik-newsletter.git/blob - newsletter/models.py
a689138084d69aa460eae02d58066b061d23c007
[django-panik-newsletter.git] / newsletter / models.py
1 import datetime
2 import hashlib
3 import random
4 import smtplib
5 import subprocess
6 from email.mime.multipart import MIMEMultipart
7 from email.mime.text import MIMEText
8
9 import html2text
10 import requests
11 from ckeditor.fields import RichTextField
12 from django.conf import settings
13 from django.core.mail import send_mail
14 from django.db import IntegrityError, models
15 from django.template import loader
16 from django.template.loader import render_to_string
17 from django.urls import reverse
18 from django.utils.encoding import force_bytes
19 from django.utils.safestring import mark_safe
20 from django.utils.translation import ugettext
21 from django.utils.translation import ugettext_lazy as _
22
23
24 class Subscriber(models.Model):
25     email = models.EmailField(unique=False)
26     inscription_date = models.DateTimeField(auto_now_add=True)
27     is_validated = models.NullBooleanField()
28     is_registered = models.NullBooleanField()
29     password = models.CharField(max_length=100)
30     bot_check1 = models.BooleanField(default=False)
31     bot_check2 = models.BooleanField(default=False)
32     user_agent = models.CharField(max_length=1000, blank=True)
33     source_ip = models.CharField(max_length=100, blank=True)
34
35     def __unicode__(self):
36         return self.email
37
38     def is_from_bot(self):
39         return bool(self.bot_check1 or self.bot_check2)
40
41     def send_confirmation_email(self):
42         if self.is_from_bot():
43             return
44         self.password = hashlib.sha1(force_bytes(str(random.random()))).hexdigest()
45         confirm_subject = loader.get_template('newsletter/confirmation_email_subject.txt')
46         confirm_body = loader.get_template('newsletter/confirmation_email_body.txt')
47         context = {'token': self.password}
48         send_mail(
49             confirm_subject.render(context).strip(),
50             confirm_body.render(context),
51             settings.NEWSLETTER_SENDER,
52             [self.email],
53         )
54         self.is_validated = False
55         self.save()
56
57     def subscribe(self):
58         newsletter_service = getattr(settings, 'NEWSLETTER_SERVICE', 'mailman')
59         if newsletter_service == 'mailman':
60             return self.subscribe_in_mailman()
61         elif newsletter_service == 'mailchimp':
62             return self.subscribe_in_mailchimp()
63
64     def subscribe_in_mailman(self):
65         try:
66             subprocess.run(['listadmin', '--add-member', self.email, settings.NEWSLETTER_NAME], check=True)
67         except subprocess.CalledProcessError:
68             # maybe an error because email is already registered?
69             result = subprocess.run(
70                 ['listadmin', '-l', settings.NEWSLETTER_NAME], check=True, capture_output=True, text=True
71             )
72             if self.email in result.stdout.splitlines():
73                 self.is_registered = True
74                 self.save()
75             return
76         self.is_registered = True
77         self.save()
78
79     def subscribe_in_mailchimp(self):
80         dc = settings.MAILCHIMP_DC
81         apikey = settings.MAILCHIMP_APIKEY
82         list_id = settings.MAILCHIMP_LIST_ID
83         self.email = self.email.lower()
84
85         email_hash = hashlib.md5(self.email.encode()).hexdigest()
86
87         resp = requests.put(
88             f'https://{dc}.api.mailchimp.com/3.0/lists/{list_id}/members/{email_hash}',
89             auth=('key', apikey),
90             json={
91                 'email_address': self.email,
92                 'status_if_new': 'subscribed',
93             },
94         )
95         if resp.ok and resp.json().get('status') == 'subscribed':
96             self.is_registered = True
97             self.save()
98
99
100 class Newsletter(models.Model):
101     class Meta:
102         verbose_name = _('Newsletter')
103         verbose_name_plural = _('Newsletters')
104         ordering = ['date']
105
106     subject = models.CharField(_('Title'), max_length=50)
107     date = models.DateField(_('Date'))
108     text = RichTextField(_('Text'), null=True, blank=True)
109
110     expedition_datetime = models.DateTimeField(_('Expedition Date/time'), null=True, blank=True)
111
112     def send(self):
113         msg = MIMEMultipart('alternative')
114         msg['Subject'] = self.subject
115         msg['From'] = settings.NEWSLETTER_SENDER
116         msg['To'] = '%s@%s' % (settings.NEWSLETTER_NAME, settings.NEWSLETTER_DOMAIN)
117
118         h2t = html2text.HTML2Text()
119         h2t.unicode_snob = True
120         context = {
121             'text_part': mark_safe(h2t.handle(self.text)),
122             'html_part': mark_safe(self.text),
123         }
124
125         part1 = MIMEText(render_to_string('newsletter/email_body.txt', context), 'plain', _charset='utf-8')
126         part2 = MIMEText(render_to_string('newsletter/email_body.html', context), 'html', _charset='utf-8')
127
128         msg.attach(part1)
129         msg.attach(part2)
130
131         s = smtplib.SMTP('localhost')
132         s.sendmail(msg['From'], msg['To'], msg.as_string())
133         s.quit()
134
135         self.expedition_datetime = datetime.datetime.now()
136         self.save()
137
138     def get_absolute_url(self):
139         return reverse('newsletter-view', kwargs={'pk': self.id})