-# -*- coding: utf8 -*-
-
import datetime
import hashlib
import random
import smtplib
import subprocess
-
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import html2text
-
-from django.db import models
-from django.core.urlresolvers import reverse
-
+import mechanize
+import requests
+from ckeditor.fields import RichTextField
+from django.conf import settings
+from django.core.mail import send_mail
+from django.db import IntegrityError, models
from django.template import loader
from django.template.loader import render_to_string
-from django.conf import settings
-
+from django.urls import reverse
+from django.utils.encoding import force_bytes
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext
from django.utils.translation import ugettext_lazy as _
-from django.core.mail import send_mail
-from ckeditor.fields import RichTextField
+class Subscriber(models.Model):
+ email = models.EmailField(unique=False)
+ inscription_date = models.DateTimeField(auto_now_add=True)
+ is_validated = models.NullBooleanField()
+ is_registered = models.NullBooleanField()
+ password = models.CharField(max_length=100)
+ bot_check1 = models.BooleanField(default=False)
+ bot_check2 = models.BooleanField(default=False)
+ user_agent = models.CharField(max_length=1000, blank=True)
+ source_ip = models.CharField(max_length=100, blank=True)
-class Subscriber(models.Model) :
- email = models.EmailField(unique = True) # TODO : informer si déjà inscrit ? Que faire dans ce cas.
- inscription_date = models.DateField(auto_now_add=True)
- is_validated = models.NullBooleanField() # Au click sur le lien de confirmation. Null si erreur à l'envoi au souscripteur.
- is_registered = models.NullBooleanField() # À l'inscription après la confirmation Null si erreur à l'envoi à mailman.
- password = models.CharField(max_length=100) # sha1
-
- def __unicode__(self) :
+ def __unicode__(self):
return self.email
- def save(self, *args, **kwargs):
- super(Subscriber, self).save(*args, **kwargs)
- if self.is_validated is None:
- self.send_confirmation_email()
+ def is_from_bot(self):
+ return bool(self.bot_check1 or self.bot_check2)
def send_confirmation_email(self):
- self.password = hashlib.sha1(str(random.random())).hexdigest()
+ if self.is_from_bot():
+ return
+ self.password = hashlib.sha1(force_bytes(str(random.random()))).hexdigest()
confirm_subject = loader.get_template('newsletter/confirmation_email_subject.txt')
confirm_body = loader.get_template('newsletter/confirmation_email_body.txt')
context = {'token': self.password}
- send_mail(confirm_subject.render(context).strip(), confirm_body.render(context),
- settings.NEWSLETTER_SENDER, [self.email])
+ send_mail(
+ confirm_subject.render(context).strip(),
+ confirm_body.render(context),
+ settings.NEWSLETTER_SENDER,
+ [self.email],
+ )
self.is_validated = False
self.save()
+ def subscribe(self):
+ newsletter_service = getattr(settings, 'NEWSLETTER_SERVICE', 'mailman')
+ if newsletter_service == 'mailman':
+ return self.subscribe_in_mailman()
+ elif newsletter_service == 'mailman3':
+ return self.subscribe_in_mailman3()
+ elif newsletter_service == 'mailchimp':
+ return self.subscribe_in_mailchimp()
+
def subscribe_in_mailman(self):
- t = subprocess.call(['listadmin', '--add-member', self.email, settings.NEWSLETTER_NAME])
- if t != 0:
+ try:
+ subprocess.run(['listadmin', '--add-member', self.email, settings.NEWSLETTER_NAME], check=True)
+ except subprocess.CalledProcessError:
+ # maybe an error because email is already registered?
+ result = subprocess.run(
+ ['listadmin', '-l', settings.NEWSLETTER_NAME], check=True, capture_output=True, text=True
+ )
+ if self.email in result.stdout.splitlines():
+ self.is_registered = True
+ self.save()
return
self.is_registered = True
self.save()
+ def subscribe_in_mailman3(self):
+ # emulate browser to login and subscribe user
+ br = mechanize.Browser()
+ br.open(settings.NEWSLETTER_MAILMAN3_LIST_URL)
+ br.follow_link(url_regex=re.compile('/accounts/login'))
+ br.select_form(action=lambda x: '/login/' in x)
+ br['login'] = settings.NEWSLETTER_MAILMAN3_LOGIN
+ br['password'] = settings.NEWSLETTER_MAILMAN3_PASSWORD
+ response = br.submit()
+ assert br.find_link(url_regex=re.compile('/accounts/logout'))
+ br.open(settings.NEWSLETTER_MAILMAN3_LIST_URL + 'mass_subscribe/')
+ br.select_form(action=lambda x: '/mass_subscribe/' in x)
+ br['emails'] = self.email
+ br['pre_confirmed'] = ['on']
+ br['pre_approved'] = ['on']
+ br['pre_verified'] = ['on']
+ br['send_welcome_message'] = ['False']
+ response = br.submit()
+ self.is_registered = True
+ self.save()
+
+ def subscribe_in_mailchimp(self):
+ dc = settings.MAILCHIMP_DC
+ apikey = settings.MAILCHIMP_APIKEY
+ list_id = settings.MAILCHIMP_LIST_ID
+ self.email = self.email.lower()
-class Newsletter(models.Model):
+ email_hash = hashlib.md5(self.email.encode()).hexdigest()
+
+ resp = requests.put(
+ f'https://{dc}.api.mailchimp.com/3.0/lists/{list_id}/members/{email_hash}',
+ auth=('key', apikey),
+ json={
+ 'email_address': self.email,
+ 'status_if_new': 'subscribed',
+ },
+ )
+ if resp.ok and resp.json().get('status') == 'subscribed':
+ self.is_registered = True
+ self.save()
+
+class Newsletter(models.Model):
class Meta:
verbose_name = _('Newsletter')
verbose_name_plural = _('Newsletters')
msg = MIMEMultipart('alternative')
msg['Subject'] = self.subject
msg['From'] = settings.NEWSLETTER_SENDER
- if settings.DEBUG:
- msg['To'] = 'fred@localhost'
- else:
- msg['To'] = '%s@%s' % (settings.NEWSLETTER_NAME, settings.NEWSLETTER_DOMAIN)
+ msg['To'] = '%s@%s' % (settings.NEWSLETTER_NAME, settings.NEWSLETTER_DOMAIN)
h2t = html2text.HTML2Text()
h2t.unicode_snob = True