newsletter announces

remotes/origin/1203
Nazar Kotjuk 10 years ago
parent 9963687752
commit 17834aa692
  1. 2
      article/admin.py
  2. 2
      article/forms.py
  3. 31
      country/management/commands/newsletter_create_dependies.py
  4. 2
      emencia/django/newsletter/admin_forms.py
  5. 4
      emencia/django/newsletter/admin_urls.py
  6. 132
      emencia/django/newsletter/mailer.py
  7. 18
      emencia/django/newsletter/management/commands/newsletter_create_announce.py
  8. 74
      emencia/django/newsletter/models.py
  9. 2
      emencia/django/newsletter/settings.py
  10. 176
      emencia/django/newsletter/templates/newsletter/announce_template.html
  11. 16
      emencia/django/newsletter/templates/newsletter/newsletter_link_unsubscribe.html
  12. 2
      emencia/django/newsletter/urls/__init__.py
  13. 32
      emencia/django/newsletter/views/admin_views.py
  14. 1
      templates/admin/article/blog_form.html
  15. 2
      templates/admin/newsletters/newsletter_list.html

@ -231,7 +231,7 @@ class NewsList(ListView):
class NewsView(BlogView):
form_class = NewsForm
template_name = 'article/blog_form.html'
template_name = 'admin/article/blog_form.html'
success_url = '/admin/article/news/all/'
obj = None

@ -21,7 +21,7 @@ class BlogForm(forms.Form):
type = Article.blog
theme = forms.ModelMultipleChoiceField(label='Тематики', queryset=ThemeBlog.objects.all(), required=False,
widget=forms.SelectMultiple(attrs={'style':'width: 550px'}))
slug = forms.SlugField(label=u'URL', max_length=255, min_length=1)
slug = forms.SlugField(label=u'URL', max_length=255, min_length=1, required=False)
publish_date = forms.DateField(label=u'Дата публикации', input_formats=['%Y-%m-%d', '%d.%m.%Y'], required=False)
tag = forms.CharField(label=u'Теги', widget=forms.HiddenInput(), required=False)
logo = forms.ImageField(label=u'Лого', required=False)

@ -0,0 +1,31 @@
# create default test newsletter for announce with attachments
"""Command for sending the newsletter"""
from django.conf import settings
from django.utils.translation import activate
from django.core.management.base import NoArgsCommand
from emencia.django.newsletter.mailer import Mailer
from emencia.django.newsletter.models import Newsletter, MailingList, SMTPServer, Contact
class Command(NoArgsCommand):
"""Send the newsletter in queue"""
help = 'create the announce every week'
def handle(self, *args, **options):
# creating smtp server
try:
server = SMTPServer.objects.get(id=1)
except SMTPServer.DoesNotExist:
server = SMTPServer.objects.create(id=1, name='default', host='smtp.gmail.com', user='kotzillla',
password='fitteR2006!!', port=587, tls=True, mails_hour=1000)
# mailinglist for announce
try:
mail_list = MailingList.objects.get(id=1)
except SMTPServer.DoesNotExist:
mail_list = MailingList.objects.create(id=1, name=u'Анонсы', announce=True)
# add subscribers
mail_list.subscribers.add(Contact.objects.filter(contactsettings__theme__isnull=False))

@ -58,8 +58,6 @@ class NewsletterForm(forms.ModelForm):
fields = ('title', 'content', 'mailing_list', 'test_contacts', 'header_sender',
'header_reply', 'status', 'sending_date', 'slug')
def clean_test_contacts(self):
return []
class AttachmentForm(forms.ModelForm):
class Meta:

@ -9,8 +9,12 @@ from emencia.django.newsletter.views.admin_views import ContactList, UpdateConta
urlpatterns = patterns('',
url(r'^newsletters/all/$', NewsletterListView.as_view(), name='newsletters_newsletters_list'),
url(r'^newsletters/(?P<pk>\d+)/edit/', NewsletterUpdate.as_view(), name='newsletters_newsletters_update'),
url(r'^newsletters/(?P<pk>\d+)/test/',
'emencia.django.newsletter.views.admin_views.send_test_newsletter',
name='newsletters_newsletters_send_test'),
url(r'^newsletters/', NewsletterCreate.as_view(), name='newsletters_newsletters_create'),
url(r'^mailinglist/all/$', MailingListView.as_view(), name='newsletters_mailinglist'),
url(r'^mailinglist/(?P<pk>\d+)/edit/', UpdateMailingList.as_view(), name='newsletters_mailinglist_update'),
url(r'^mailinglist/', CreateMailingList.as_view(), name='newsletters_mailinglist_create'),

@ -30,7 +30,7 @@ from email import message_from_file
from html2text import html2text as html2text_orig
from django.contrib.sites.models import Site
from django.template import Context, Template
from django.template.loader import render_to_string
from django.template.loader import render_to_string, get_template
from django.utils.encoding import smart_str
from django.utils.encoding import smart_unicode
from django.core.urlresolvers import reverse
@ -71,17 +71,7 @@ def html2text(html):
https://github.com/aaronsw/html2text/issues/#issue/7 is not fixed"""
txt = html2text_orig(html)
return txt
"""
links = list(LINK_RE.finditer(txt))
out = StringIO()
pos = 0
for l in links:
out.write(txt[pos:l.start()])
out.write(l.group().replace('\n', ''))
pos = l.end()
out.write(txt[pos:])
return out.getvalue()
"""
def encodestring(instring, tabs=0):
outfile = StringIO()
@ -101,14 +91,18 @@ class NewsLetterSender(object):
self.newsletter = newsletter
self.newsletter_template = Template(self.newsletter.content)
self.title_template = Template(self.newsletter.title)
#
self.announce = self.newsletter.mailing_list.announce
def build_message(self, contact):
def build_message(self, contact, announce_context=None):
"""
Build the email as a multipart message containing
a multipart alternative for text (plain, HTML) plus
all the attached files.
"""
content_html = self.build_email_content(contact)
content_html = self.build_email_content(contact, announce_context)
h = HTMLParser.HTMLParser()
content_html = h.unescape(content_html)
content_text = html2text(content_html)
@ -139,6 +133,12 @@ class NewsLetterSender(object):
for attachment in self.attachments:
message.attach(attachment)
if announce_context:
# add announce attachments
announce_attachments = self.build_announce_attachments(announce_context)
for attachment in announce_attachments:
message.attach(attachment)
for header, value in self.newsletter.server.custom_headers.items():
message[header] = value
@ -147,8 +147,6 @@ class NewsLetterSender(object):
message['List-Unsubscribe'] = '<' + unsubscribe_link + '>'
message['List-Id'] = str(self.newsletter.id)
return message
def build_attachments(self):
@ -185,6 +183,61 @@ class NewsLetterSender(object):
return attachments
def build_announce_attachments(self, context):
# todo: move hardcoded prefixes to setting
events = context['events']
news = context.get('news')
blogs = context.get('blogs')
attachments = []
for event in events:
message_attachment = self.gen_attachment_logo(event, prefix='mail_expo_logo_')
if message_attachment:
attachments.append(message_attachment)
if news:
for item in news:
message_attachment = self.gen_attachment_logo(item, prefix='mail_news_logo_')
if message_attachment:
attachments.append(message_attachment)
if blogs:
for item in blogs:
message_attachment = self.gen_attachment_logo(item, prefix='mail_blogs_logo_')
if message_attachment:
attachments.append(message_attachment)
return attachments
def gen_attachment_logo(self, obj, prefix='logo_'):
logo = getattr(obj, 'logo')
if not logo:
return None
ctype, encoding = mimetypes.guess_type(logo.path)
if ctype is None or encoding is not None:
ctype = 'application/octet-stream'
maintype, subtype = ctype.split('/', 1)
try:
fd = open(logo.path, 'rb')
except IOError:
return None
if maintype == 'image':
message_attachment = MIMEImage(fd.read(), _subtype=subtype)
else:
message_attachment = MIMEBase(maintype, subtype)
message_attachment.set_payload(fd.read())
encode_base64(message_attachment)
fd.close()
cid = prefix + '%d'%obj.id
message_attachment.add_header('Content-ID', '<%s>'%cid)
return message_attachment
def build_title_content(self, contact):
"""Generate the email title for a contact"""
context = Context({'contact': contact,
@ -193,7 +246,7 @@ class NewsLetterSender(object):
title = self.title_template.render(context)
return title
def build_email_content(self, contact):
def build_email_content(self, contact, announce_context=None):
"""Generate the mail for a contact"""
uidb36, token = tokenize(contact)
context = Context({'contact': contact,
@ -201,13 +254,19 @@ class NewsLetterSender(object):
'newsletter': self.newsletter,
'tracking_image_format': TRACKING_IMAGE_FORMAT,
'uidb36': uidb36, 'token': token})
content = self.newsletter_template.render(context)
if self.announce:
# render template by default announce template
template = get_template('newsletter/announce_template.html')
context.update(announce_context)
content = template.render(context)
else:
content = self.newsletter_template.render(context)
if TRACKING_LINKS:
content = track_links(content, context)
link_site = render_to_string('newsletter/newsletter_link_site.html', context)
content = body_insertion(content, link_site)
# uncomment if wanna include this link
#link_site = render_to_string('newsletter/newsletter_link_site.html', context)
#content = body_insertion(content, link_site)
if INCLUDE_UNSUBSCRIPTION:
@ -217,9 +276,7 @@ class NewsLetterSender(object):
if TRACKING_IMAGE:
image_tracking = render_to_string('newsletter/newsletter_image_tracking.html', context)
content = body_insertion(content, image_tracking, end=True)
#return content
#return encodestring(content)
return smart_unicode(content)
def update_newsletter_status(self):
@ -258,8 +315,10 @@ class NewsLetterSender(object):
expedition_list = self.newsletter.mailing_list.expedition_set().exclude(id__in=already_sent)
return expedition_list
def update_contact_status(self, contact, exception):
if exception is None:
def update_contact_status(self, contact, exception, send):
if not send:
status = ContactMailingStatus.ANNOUNCE_NO_DATA
elif exception is None:
status = (self.test
and ContactMailingStatus.SENT_TEST
or ContactMailingStatus.SENT)
@ -299,21 +358,30 @@ class Mailer(NewsLetterSender):
i = 1
for contact in expedition_list:
send = True
if self.verbose:
print '- Processing %s/%s (%s)' % (
i, number_of_recipients, contact.pk)
message = self.build_message(contact)
self.smtp.sendmail(self.newsletter.header_sender,
contact.email,
message.as_string())
try:
pass
if self.announce:
# check if events for this newsletter exists
announce_context = contact.get_announce_context()
if not announce_context:
send = False
else:
announce_context = None
try:
if send:
message = self.build_message(contact, announce_context)
self.smtp.sendmail(self.newsletter.header_sender,
contact.email,
message.as_string())
except Exception, e:
exception = e
else:
exception = None
self.update_contact_status(contact, exception)
self.update_contact_status(contact, exception, send)
if SLEEP_BETWEEN_SENDING:
time.sleep(SLEEP_BETWEEN_SENDING)

@ -0,0 +1,18 @@
"""Command for sending the newsletter"""
from datetime import date, timedelta
from django.conf import settings
from django.utils.translation import activate
from django.core.management.base import NoArgsCommand
from emencia.django.newsletter.mailer import Mailer
from emencia.django.newsletter.models import Newsletter, MailingList
class Command(NoArgsCommand):
"""this command run every day. check date and creates newsletter the day before announces need to send"""
help = 'create the announce every week.'
def handle(self, *args, **options):
announce_list = MailingList.objects.get(id=1)
day = date.today()# + timedelta(days=1)
announce_list.generate_announce_newsletter(day)

@ -26,7 +26,7 @@ from emencia.django.newsletter.settings import BASE_PATH
from emencia.django.newsletter.settings import MAILER_HARD_LIMIT
from emencia.django.newsletter.settings import DEFAULT_HEADER_REPLY
from emencia.django.newsletter.settings import DEFAULT_HEADER_SENDER
from emencia.django.newsletter.settings import ACTIVATION_SUBJECT, ACTIVATION_TEMPLATE
from emencia.django.newsletter.settings import ACTIVATION_SUBJECT, ACTIVATION_TEMPLATE, DEFAULT_SMPTSERVER_ID
from emencia.django.newsletter.utils.vcard import vcard_contact_export
from emencia.django.newsletter.utils import make_activation_code
@ -152,6 +152,41 @@ class Contact(models.Model):
return self.content_object.get_absolute_url()
return reverse('admin:newsletter_contact_change', args=(self.pk,))
def get_announce_context(self):
from exposition.models import Exposition
from article.models import Article
from django.utils.translation import activate
activate('ru')
events = Exposition.enable.upcoming()
themes = list(self.contactsettings.theme.all())
try:
country = self.contactsettings.country.all()[0]
except IndexError:
country = None
if themes:
theme_ids = [item.id for item in themes]
events = events.filter(theme__in=theme_ids)
else:
return None
if country:
events = events.filter(country=country)
events = list(events[:3])
if events:
context = {'themes': themes, 'place': country, 'events': events}
else:
# no events for announce
return None
news = list(Article.objects.news().filter(publish_date__gt=datetime.now()-timedelta(days=7))[:3])
if news:
context['news'] = news
blogs = list(Article.objects.blogs().filter(publish_date__gt=datetime.now()-timedelta(days=7))[:3])
if blogs:
context['blogs'] = blogs
return context
def __unicode__(self):
if self.first_name and self.last_name:
contact_name = '%s %s' % (self.last_name, self.first_name)
@ -246,6 +281,39 @@ class MailingList(models.Model):
def __unicode__(self):
return self.name
def check_day(self, day):
weekday = day.weekday()
if self.announce_public_day > 0:
return (self.announce_public_day - 1) == weekday
else:
return weekday == 6
def generate_announce(self, day):
# simple data
sending_date = day + timedelta(days=1)
start_sending_time = datetime.combine(sending_date, datetime.min.time())
title = u'announce_%s'%sending_date.strftime('%Y_%m_%y')
newsletter = Newsletter(status=Newsletter.WAITING, sending_date=start_sending_time,
title=title, mailing_list=self, slug=title)
newsletter.save()
# add default attacments copied from default announce newsletter
default_newsletter = Newsletter.objects.get(id=1)
attacments = list(default_newsletter.attachment_set.all())
for a in attacments:
a.id = None
a.newsletter = newsletter
a.save()
return newsletter
def generate_announce_newsletter(self, day):
if self.check_day(day):
return self.generate_announce(day)
return None
class Meta:
ordering = ('-creation_date',)
verbose_name = _('mailing list')
@ -278,7 +346,7 @@ class Newsletter(models.Model):
blank=True, null=True)
server = models.ForeignKey(SMTPServer, verbose_name=_('smtp server'),
default=lambda: SMTPServer.objects.get(id=1))
default=lambda: SMTPServer.objects.get(id=DEFAULT_SMPTSERVER_ID))
header_sender = models.CharField(_('sender'), max_length=255,
default=DEFAULT_HEADER_SENDER)
header_reply = models.CharField(_('reply to'), max_length=255,
@ -376,6 +444,7 @@ class ContactMailingStatus(models.Model):
OPENED_ON_SITE = 5
LINK_OPENED = 6
UNSUBSCRIPTION = 7
ANNOUNCE_NO_DATA = 8
STATUS_CHOICES = ((SENT_TEST, _('sent in test')),
(SENT, _('sent')),
@ -385,6 +454,7 @@ class ContactMailingStatus(models.Model):
(OPENED_ON_SITE, _('opened on site')),
(LINK_OPENED, _('link opened')),
(UNSUBSCRIPTION, _('unsubscription')),
(ANNOUNCE_NO_DATA, _('announce no data')),
)
newsletter = models.ForeignKey(Newsletter, verbose_name=_('newsletter'))

@ -41,3 +41,5 @@ BASE_PATH = getattr(settings, 'NEWSLETTER_BASE_PATH', 'uploads/newsletter')
ACTIVATION_SUBJECT = 'client/newsletters/activation_subject.txt'
ACTIVATION_TEMPLATE = 'client/newsletters/activation_template.html'
DEFAULT_SMPTSERVER_ID = 1

@ -0,0 +1,176 @@
<body style="margin: 0; padding: 0; min-height: 100%; background: #f4f2ee;">
<table cellpadding="0" cellspacing="0" border="0" width="100%" height="100%" bgcolor="#f4f2ee" style="font-family: Arial, sans-serif; background: #f4f2ee;">
<tr>
<td align="center" style="padding: 50px 0">
{# header #}
<table cellpadding="0" cellspacing="0" border="0" width="600" style="width: 600px;">
<tr>
<td style="vertical-align: top;">
<div class="logo">
<a style="text-decoration: none; color: #a2a2a2; font-size: 12px;" href="/">
<img src="cid:logo" alt="Expomap.ru" />
<b style="display: block; padding-left: 67px; margin-top: -5px;">Выставки, конференции, семинары</b>
</a>
</div>
</td>
<td style="vertical-align: top; padding-top: 22px;">
<ul class="t-links" style="margin: 0 0 15px; padding: 0; list-style: none; text-align: right; font-size: 16px; line-height: 17px; font-weight: bold;">
<li style="display: inline-block;"><a style="text-decoration: none; color: #ff6600" href="/expo/">СОБЫТИЯ</a></li>
<li style="display: inline-block; margin-left: 20px;"><a style="text-decoration: none; color: #ff6600" href="/places/">МЕСТА</a></li>
<li style="display: inline-block; margin-left: 20px;"><a style="text-decoration: none; color: #ff6600" href="/members/">УЧАСТНИКИ</a></li>
</ul>
<ul class="soc-media-buttons" style="margin: 0; padding: 0; list-style: none; text-align: right;">
<li style="display: inline-block; margin-left: 5px;"><a href="https://www.facebook.com/Expomap"><img src="cid:media_fb" title="Facebook" alt="Facebook" /></a></li>
<li style="display: inline-block; margin-left: 5px;"><a href="http://www.linkedin.com/company/expomap-ru/"><img src="cid:media_lin" title="LinkedIn" alt="LinkedIn" /></a></li>
<li style="display: inline-block; margin-left: 5px;"><a href="http://vk.com/expomap"><img src="cid:media_vk" title="В контакте" alt="В контакте" /></a></li>
<li style="display: inline-block; margin-left: 5px;"><a href="https://twitter.com/expomap_ru"><img src="cid:media_twit" title="Twitter" alt="Twitter" /></a></li>
</ul>
</td>
</tr>
</table>
{# end header #}
{# events #}
{% with events=events %}
<table cellpadding="0" cellspacing="0" border="0" width="600" style="width: 600px; margin-bottom: 10px;">
<tr>
<td style="padding: 20px 0 0;"><a style="display: block; padding: 25px 30px; text-decoration: none; background: #ff6600; color: #ffffff; font-size: 20px; line-height: 26px;" href="/expo/search/?{% for th in themes %}th={{ th.id }}&{% endfor %}{% if place %}co={{ place.id }}&{% endif %}">Выставки{% if place %} {{ place.inflect }}{% endif %} {% if themes|length == 1 %}по тематике:<b style="display: block; font-size: 26px;">{{ themes.0.name }}</b>{% endif %}</a></td>
</tr>
<tr>
<td style="padding: 10px 30px 15px; background: #faf9f7;">
<table cellpadding="0" cellspacing="0" border="0" width="540" style="margin-bottom: 15px;">
{% for event in events %}
<tr valign="top">
<td style="padding: 15px 15px 15px 0; width: 76px; border-bottom: 1px dotted #cccccc;">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td style="background: #ffffff; padding: 3px; width: 70px; height: 70px; vertical-align: middle; text-align: center; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px;"><a href="http://{{ domain }}{{ event.get_permanent_url }}"><img src="cid:mail_expo_logo_{{ event.id }}" style="width: 100%;" alt="" /></a></td>
</tr>
</table>
</td>
<td style="padding: 15px 15px 15px 0; border-bottom: 1px dotted #cccccc;">
<h2 style="margin: 0 0 5px; font-family: Tahoma, Arial, sans-serif; font-size: 18px; line-height: 21px;"><a style="color: #464646; text-decoration: none;" href="http://{{ domain }}{{ event.get_permanent_url }}">{{ event.name }}</a></h2>
<p style="margin: 0 0 7px; font-size: 12px; line-height: 15px; color: #a2a2a2"><a style="color: #a2a2a2; text-decoration: none;" href="http://{{ domain }}{{ event.get_permanent_url }}">{{ obj.main_title|safe }}</a></p>
<a class="button" style="display: inline-block; padding: 4px 10px 3px; text-decoration: none; color: #ff6600; font-size: 11px; font-weight: bold; line-height: 14px; border: 1px solid #feb17d; text-transform: uppercase; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px;" href="http://{{ domain }}{{ event.get_permanent_url }}">добавить в расписание</a>
<div class="addr" style="margin-top: 10px; font-size: 13px; line-height: 15px;"><img src="cid:pin" width="10" height="15" alt="" style="vertical-align: middle; margin-top: -1px;" /> {{ event.country.name }}, {{ event.city.name }}{% if event.place %}, {{ event.place.name }}{% endif %}</div>
</td>
<td style="padding: 17px 0; text-align: right; font-size: 13px; line-height: 16px; color: #ff6600; width: 140px; border-bottom: 1px dotted #cccccc;">
<img src="cid:clock" width="14" height="15" style="vertical-align: middle; margin-top: -1px;" alt="" /> {% include 'client/includes/show_date_block.html' with obj=event %}
</td>
</tr>
{% endfor %}
</table>
<div class="more" style="text-align: center;">
<a class="button" style="display: inline-block; padding: 4px 10px 3px; text-decoration: none; color: #2592c5; font-size: 11px; font-weight: bold; line-height: 14px; border: 1px solid #90c7e0; text-transform: uppercase; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; width: 336px;" href="/expo/">посмотреть все события</a>
</div>
</td>
</tr>
</table>
{% endwith %}
{# end events #}
{% if news %}
<table cellpadding="0" cellspacing="0" border="0" width="600" style="width: 600px; margin-bottom: 10px;">
<tr>
<td style="padding: 20px 0 0;"><a style="display: block; padding: 25px 30px; text-decoration: none; background: #ff6600; color: #ffffff; font-size: 20px; line-height: 26px;" href="/news/">Новости событий</a></td>
</tr>
<tr>
<td style="padding: 10px 30px 15px; background: #faf9f7;">
<table cellpadding="0" cellspacing="0" border="0" width="540" style="margin-bottom: 15px;">
{% for item in news %}
<tr valign="top">
<td style="padding: 15px 15px 15px 0; width: 76px; border-bottom: 1px dotted #cccccc;">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td style="background: #ffffff; padding: 0; width: 76px; height: 76px; vertical-align: middle; text-align: center;"><a href="{{ item.get_permanent_url }}"><img style="width: 100%; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px;" alt="" src="cid:mail_news_logo_{{ item.id }}" /></a></td>
</tr>
</table>
</td>
<td style="padding: 15px 0; border-bottom: 1px dotted #cccccc;">
<table cellpadding="0" cellspacing="0" border="0" width="100%" style="margin-bottom: 5px;">
<tr>
<td><h2 style="margin: 0 0 5px; font-family: Tahoma, Arial, sans-serif; font-size: 18px; line-height: 21px;"><a style="color: #464646; text-decoration: none;" href="{{ item.get_permanent_url }}">{{ item.main_title }}</a></h2></td>
<td style="font-size: 13px; line-height: 15px; text-align: right; color: #ff6600;">{{ item.publish_date|date:"d.m.Y" }}</td>
</tr>
</table>
<p style="margin: 0 0 7px; font-size: 13px; line-height: 17px;"><a style="color: #464646; text-decoration: none;" href="{{ item.get_permanent_url }}">{{ item.preview }} <span style="text-decoration: underline; color: #ff6600;">...</span></a></p>
</td>
</tr>
{% endfor %}
</table>
<div class="more" style="text-align: center;">
<a class="button" style="display: inline-block; padding: 4px 10px 3px; text-decoration: none; color: #2592c5; font-size: 11px; font-weight: bold; line-height: 14px; border: 1px solid #90c7e0; text-transform: uppercase; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; width: 336px;" href="/news/">посмотреть все новости</a>
</div>
</td>
</tr>
</table>
{% endif %}
{% if blogs %}
<table cellpadding="0" cellspacing="0" border="0" width="600" style="width: 600px; margin-bottom: 10px;">
<tr>
<td style="padding: 20px 0 0;"><a style="display: block; padding: 25px 30px; text-decoration: none; background: #ff6600; color: #ffffff; font-size: 20px; line-height: 26px;" href="/blogs/">Аналитика для профессионалов</a></td>
</tr>
<tr>
<td style="padding: 10px 30px 15px; background: #faf9f7;">
<table cellpadding="0" cellspacing="0" border="0" width="540">
{% for item in blogs %}
<tr valign="top">
<td style="padding: 15px 15px 0 0; width: 76px;">
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td style="background: #ffffff; padding: 0; width: 76px; height: 76px; vertical-align: middle; text-align: center;"><a href="{{ item.get_permanent_url }}"><img style="width: 100%; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px;" alt="" src="cid:mail_blogs_logo_{{ item.id }}" /></a></td>
</tr>
</table>
</td>
<td style="padding: 15px 0 0;">
<h2 style="margin: 0 0 5px; font-family: Tahoma, Arial, sans-serif; font-size: 18px; line-height: 21px;"><a style="color: #464646; text-decoration: none;" href="{{ item.get_permanent_url }}">{{ item.main_title }}</a></h2>
<p style="margin: 0 0 7px; font-size: 13px; line-height: 17px;"><a style="color: #464646; text-decoration: none;" href="{{ item.get_permanent_url }}">{{ item.preview }} <span style="text-decoration: underline; color: #ff6600;">...</span></a></p>
</td>
</tr>
{% endfor %}
</table>
</td>
</tr>
</table>
{% endif %}
<table cellpadding="0" cellspacing="0" border="0" width="600" style="width: 600px; border-bottom: 1px dotted #cccccc;">
<tr>
<td style="vertical-align: top; padding: 15px 0 10px;">
<div class="logo">
<a style="text-decoration: none; color: #a2a2a2; font-size: 12px;" href="/">
<img src="cid:logo_2" alt="Expomap.ru" />
</a>
</div>
</td>
<td style="vertical-align: top; padding: 25px 0 5px;">
<ul class="t-links" style="margin: 0 0 15px; padding: 0; list-style: none; text-align: right; font-size: 14px; line-height: 15px; font-weight: bold;">
<li style="display: inline-block;"><a style="text-decoration: none; color: #ff6600" href="/expo/">СОБЫТИЯ</a></li>
<li style="display: inline-block; margin-left: 20px;"><a style="text-decoration: none; color: #ff6600" href="/places/">МЕСТА</a></li>
<li style="display: inline-block; margin-left: 20px;"><a style="text-decoration: none; color: #ff6600" href="/members/">УЧАСТНИКИ</a></li>
</ul>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>

@ -1,8 +1,14 @@
{% load i18n %}
<div id="unsubscription">
<a name="unsubscription"></a>
<p>
{% trans "For unsubscribing to this mailing list," %}
<a href="{% if uidb36 and token %}http://{{ domain }}{% url 'newsletter_mailinglist_unsubscribe' slug=newsletter.slug uidb36=uidb36 token=token %}{% else %}#{% endif %}">{% trans "click here" %}</a>.
</p>
<table border="0" cellpadding="0" cellspacing="0" style="font-size: 12px; line-height: 15px; font-family: Arial, sans-serif; background: #f4f2ee;" width="100%" bgcolor="#f4f2ee" >
<tbody>
<tr>
<td style="vertical-align: top; padding: 15px 0 15px; text-align: center;">Чтобы отписаться от этой рассылки, перейдите <a href="{% if uidb36 and token %}http://{{ domain }}{% url 'newsletter_mailinglist_unsubscribe' slug=newsletter.slug uidb36=uidb36 token=token %}{% else %}#{% endif %}">по ссылке</a>.
<td style="vertical-align: top; padding: 15px 0 15px; color: #a2a2a2; text-align: left;">&copy; 2018 &mdash; 2013 <a href="#" style="color: #a2a2a2; text-decoration: none;">Expomap.ru</a></td>
</tr>
</tbody>
</table>
</div>

@ -16,5 +16,5 @@ urlpatterns = patterns('',
url(r'^activation/complete/', TemplateView.as_view(template_name='client/newsletters/activation_complete.html'),
name='subscription_activation_complete'),
url(r'^activate/(?P<activation_key>.*)/$', ActivationView.as_view(), name='subscription_activation'),
url(r'^', SubscribeView.as_view(), name='newsletter_subscription'),
url(r'^$', SubscribeView.as_view(), name='newsletter_subscription'),
)

@ -1,17 +1,17 @@
# -*- coding: utf-8 -*-
from django.views.generic import TemplateView, CreateView, ListView, UpdateView, DeleteView, FormView
from django.conf import settings
from django.http import HttpResponseRedirect
from django.utils.translation import ugettext_lazy as _
from django.forms.formsets import BaseFormSet, formset_factory
from django.http import HttpResponseRedirect, HttpResponse
from django.shortcuts import get_object_or_404
from django.core.urlresolvers import reverse
from HTMLParser import HTMLParseError
from emencia.django.newsletter.models import Contact, ContactSettings, MailingList, Newsletter, Attachment
from emencia.django.newsletter.admin_forms import ContactSettingsForm, MailingListForm, NewsletterForm, AttachmentForm
from django.core.urlresolvers import reverse_lazy
from emencia.django.newsletter.models import Contact, ContactSettings, MailingList, Newsletter
from emencia.django.newsletter.admin_forms import ContactSettingsForm, MailingListForm, NewsletterForm
from emencia.django.newsletter.mailer import Mailer
from ..forms import ContactFilterForm
from ..utils.excel import ExcelResponse
from functions.admin_views import paginate_results
@ -112,9 +112,6 @@ class NewsletterCreate(CreateView):
success_url = '/admin/newsletters/newsletters/all/'
def get_formset(self):
#if self.request.POST:
# AttachmentFormSet = formset_factory(Attachment)
#else:
AttachmentFormSet = formset_factory(AttachmentForm)
if self.request.POST:
return AttachmentFormSet(self.request.POST, self.request.FILES)
@ -129,6 +126,8 @@ class NewsletterCreate(CreateView):
def form_valid(self, form):
self.object = form.save()
self.object.test_contacts = form.cleaned_data['test_contacts']
formset = self.get_formset()
if formset.is_valid():
for item in formset.forms:
@ -164,6 +163,8 @@ class NewsletterUpdate(UpdateView):
def form_valid(self, form):
self.object = form.save()
self.object.test_contacts = form.cleaned_data['test_contacts']
formset = self.get_formset()
if formset.is_valid():
for item in formset.forms:
@ -179,10 +180,23 @@ class NewsletterUpdate(UpdateView):
class NewsletterListView(ListView):
paginate_by = settings.ADMIN_PAGINATION
model = Newsletter
template_name = 'admin/newsletters/newsletter_list.html' success_url = '/admin/newsletters/newsletters/all/'
template_name = 'admin/newsletters/newsletter_list.html'
success_url = '/admin/newsletters/newsletters/all/'
from ..utils.excel import ExcelResponse
def send_test_newsletter(request, pk):
newsletter = get_object_or_404(Newsletter, pk=pk)
if newsletter.test_contacts.count():
mailer = Mailer(newsletter, test=True)
try:
mailer.run()
except HTMLParseError:
return HttpResponse(_('Unable send newsletter, due to errors within HTML.'))
else:
return HttpResponse(u'Нет тестовых контактов')
redirect = request.META.get('HTTP_REFERER', '/admin/newsletter/newsletter/all/')
return HttpResponseRedirect(redirect)
class ExportContacts(FormView):

@ -31,6 +31,7 @@
{% endblock %}
{% block body %}
{{ form.errors }}
<form method="post" class="form-horizontal" name="form2" id="form2"enctype="multipart/form-data"> {% csrf_token %}
<fieldset>
<legend><i class="icon-edit"></i>{% if article %} Изменить {% else %} Добавить {% endif %}статью{% if article %}(<a href="{{ article.get_permanent_url }}" target="_blank">на сайте</a>){% endif %}</legend>

@ -17,6 +17,7 @@
<th>Статус</th>
<th>Дата отправки</th>
<th>&nbsp;</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
@ -26,6 +27,7 @@
<td>{{ item.mailing_list }}</td>
<td>{{ item.get_status_text }}</td>
<td>{{ item.sending_date|date:"Y-m-d H:i" }}</td>
<td><a href="{% url 'newsletters_newsletters_send_test' item.id %}">тест</a> </td>
<td><a href="{% url 'newsletters_newsletters_update' item.id %}">Изменить</a> </td>
</tr>
{% endfor %}

Loading…
Cancel
Save