From 8d17d83d570b9d03000cb5c4665fa1f76cdc6194 Mon Sep 17 00:00:00 2001 From: Ivan Kovalkovskyi Date: Tue, 20 Oct 2015 17:33:42 +0300 Subject: [PATCH 1/4] newsletter history --- emencia/django/newsletter/admin_urls.py | 3 +- emencia/django/newsletter/models.py | 10 ++++ .../django/newsletter/views/admin_views.py | 21 ++++++- .../admin/newsletters/newsletter_history.html | 57 +++++++++++++++++++ .../admin/newsletters/newsletter_list.html | 2 +- 5 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 templates/admin/newsletters/newsletter_history.html diff --git a/emencia/django/newsletter/admin_urls.py b/emencia/django/newsletter/admin_urls.py index eeaa6f2b..90afd4d5 100644 --- a/emencia/django/newsletter/admin_urls.py +++ b/emencia/django/newsletter/admin_urls.py @@ -2,12 +2,13 @@ from django.conf.urls import url from django.conf.urls import patterns from emencia.django.newsletter.views.admin_views import ContactList, UpdateContact, MailingListView, UpdateMailingList,\ CreateMailingList, NewsletterListView, NewsletterCreate, ExportContacts, DeleteContact, NewsletterUpdate, \ - DeleteMailingList, ImportContacts + DeleteMailingList, ImportContacts, NewsletterHistory urlpatterns = patterns('', url(r'^newsletters/all/$', NewsletterListView.as_view(), name='newsletters_newsletters_list'), url(r'^newsletters/(?P\d+)/edit/', NewsletterUpdate.as_view(), name='newsletters_newsletters_update'), + url(r'^newsletters/(?P\d+)/history/', NewsletterHistory.as_view(), name='newsletters_newsletters_history'), url(r'^newsletters/(?P\d+)/test/', 'emencia.django.newsletter.views.admin_views.send_test_newsletter', name='newsletters_newsletters_send_test'), diff --git a/emencia/django/newsletter/models.py b/emencia/django/newsletter/models.py index 48071e40..8778d036 100644 --- a/emencia/django/newsletter/models.py +++ b/emencia/django/newsletter/models.py @@ -471,6 +471,16 @@ class ContactMailingStatus(models.Model): creation_date = models.DateTimeField(_('creation date'), auto_now_add=True) + def get_verbose_status(self): + verbose = '' + for s in self.STATUS_CHOICES: + if s[0] == self.status: + verbose = unicode(s[1]) + break + if self.status == ContactMailingStatus.LINK_OPENED: + verbose +=": %s"% (self.link.url, self.link.url) + return verbose + def __unicode__(self): return '%s : %s : %s' % (self.newsletter.__unicode__(), self.contact.__unicode__(), diff --git a/emencia/django/newsletter/views/admin_views.py b/emencia/django/newsletter/views/admin_views.py index cd62387e..d31d0f09 100644 --- a/emencia/django/newsletter/views/admin_views.py +++ b/emencia/django/newsletter/views/admin_views.py @@ -8,7 +8,7 @@ from django.http import HttpResponseRedirect, HttpResponse from django.shortcuts import get_object_or_404 from django.core.urlresolvers import reverse_lazy from HTMLParser import HTMLParseError -from emencia.django.newsletter.models import Contact, ContactSettings, MailingList, Newsletter, Attachment +from emencia.django.newsletter.models import Contact, ContactSettings, MailingList, Newsletter, Attachment, ContactMailingStatus from emencia.django.newsletter.admin_forms import ContactSettingsForm, MailingListForm, NewsletterForm, AttachmentForm from emencia.django.newsletter.mailer import Mailer from ..forms import ContactFilterForm, ContactImportForm @@ -222,6 +222,25 @@ def send_test_newsletter(request, pk): return HttpResponseRedirect(redirect) +class NewsletterHistory(ListView): + model = ContactMailingStatus + template_name = 'admin/newsletters/newsletter_history.html' + paginate_by = 50 + + def get_queryset(self): + self.newsletter = get_object_or_404(Newsletter, pk=self.kwargs['pk']) + qs = self.newsletter.contactmailingstatus_set.select_related('contact', 'link').all() + if self.request.GET.get('filter'): + qs = qs.filter(status=self.request.GET['filter']) + return qs + + def get_context_data(self, **kwargs): + context = super(NewsletterHistory, self).get_context_data(**kwargs) + context['newsletter'] = self.newsletter + context['choices'] = ContactMailingStatus.STATUS_CHOICES + return context + + class ExportContacts(FormView): form_class = ContactFilterForm diff --git a/templates/admin/newsletters/newsletter_history.html b/templates/admin/newsletters/newsletter_history.html new file mode 100644 index 00000000..f024ef90 --- /dev/null +++ b/templates/admin/newsletters/newsletter_history.html @@ -0,0 +1,57 @@ +{% extends 'admin/base.html' %} +{% load staticfiles %} +{% block body %} + +
+
+

История для {{ newsletter.title }}

+
+
+
+
+ +
+
+ + + + + + + + + + + + + + + {% for item in object_list %} + + + + + + {% endfor %} + +
ДатаКонтактСтатус
{{ item.creation_date|date:"Y-m-d H:i:s" }}{{ item.contact.email }}{{ item.get_verbose_status|safe }}
+ +
+ {# pagination #} + {% include 'admin/includes/admin_pagination.html' with page_obj=object_list %} +
+ +{% endblock %} + diff --git a/templates/admin/newsletters/newsletter_list.html b/templates/admin/newsletters/newsletter_list.html index 6f7d712a..f06a6dd3 100644 --- a/templates/admin/newsletters/newsletter_list.html +++ b/templates/admin/newsletters/newsletter_list.html @@ -31,7 +31,7 @@ {{ item.sending_date|date:"Y-m-d H:i" }} тест Изменить - История + История {% if item.status == item.SENT or item.status == item.CANCELED %}Статистика{% endif %} {% endfor %} From d1ca63840909a7dc78ea40dc8ffc3e84a508f45d Mon Sep 17 00:00:00 2001 From: Ivan Kovalkovskyi Date: Wed, 21 Oct 2015 16:21:39 +0300 Subject: [PATCH 2/4] newsletter statistics --- emencia/django/newsletter/admin_urls.py | 9 +-- .../django/newsletter/views/admin_views.py | 28 ++++++++- functions/forms.py | 17 +++-- .../admin/newsletters/newsletter_history.html | 1 + .../admin/newsletters/newsletter_list.html | 2 +- .../admin/newsletters/newsletter_stat.html | 62 +++++++++++++++++++ 6 files changed, 104 insertions(+), 15 deletions(-) create mode 100644 templates/admin/newsletters/newsletter_stat.html diff --git a/emencia/django/newsletter/admin_urls.py b/emencia/django/newsletter/admin_urls.py index 90afd4d5..4007fc9b 100644 --- a/emencia/django/newsletter/admin_urls.py +++ b/emencia/django/newsletter/admin_urls.py @@ -2,17 +2,18 @@ from django.conf.urls import url from django.conf.urls import patterns from emencia.django.newsletter.views.admin_views import ContactList, UpdateContact, MailingListView, UpdateMailingList,\ CreateMailingList, NewsletterListView, NewsletterCreate, ExportContacts, DeleteContact, NewsletterUpdate, \ - DeleteMailingList, ImportContacts, NewsletterHistory + DeleteMailingList, ImportContacts, NewsletterHistory, NewsletterStatistics urlpatterns = patterns('', url(r'^newsletters/all/$', NewsletterListView.as_view(), name='newsletters_newsletters_list'), - url(r'^newsletters/(?P\d+)/edit/', NewsletterUpdate.as_view(), name='newsletters_newsletters_update'), + url(r'^newsletters/(?P\d+)/edit/$', NewsletterUpdate.as_view(), name='newsletters_newsletters_update'), url(r'^newsletters/(?P\d+)/history/', NewsletterHistory.as_view(), name='newsletters_newsletters_history'), - url(r'^newsletters/(?P\d+)/test/', + url(r'^newsletters/(?P\d+)/statistics/', NewsletterStatistics.as_view(), name='newsletters_newsletters_stat'), + url(r'^newsletters/(?P\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'^newsletters/$', NewsletterCreate.as_view(), name='newsletters_newsletters_create'), url(r'^mailinglist/all/$', MailingListView.as_view(), name='newsletters_mailinglist'), diff --git a/emencia/django/newsletter/views/admin_views.py b/emencia/django/newsletter/views/admin_views.py index d31d0f09..1a7f4f2f 100644 --- a/emencia/django/newsletter/views/admin_views.py +++ b/emencia/django/newsletter/views/admin_views.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from django.views.generic import CreateView, ListView, UpdateView, DeleteView, FormView +from django.views.generic import CreateView, ListView, UpdateView, DeleteView, FormView, DetailView from django.conf import settings from django.utils import translation from django.utils.translation import ugettext_lazy as _ @@ -240,6 +240,32 @@ class NewsletterHistory(ListView): context['choices'] = ContactMailingStatus.STATUS_CHOICES return context +class NewsletterStatistics(DetailView): + model = Newsletter + template_name = 'admin/newsletters/newsletter_stat.html' + + def get_context_data(self, **kwargs): + context = super(NewsletterStatistics, self).get_context_data(**kwargs) + sent = self.object.contactmailingstatus_set.filter(status=ContactMailingStatus.SENT).count() + errors = self.object.contactmailingstatus_set.filter(status=ContactMailingStatus.ERROR).count() + opened = self.object.contactmailingstatus_set.filter(status=ContactMailingStatus.OPENED).count() + unsubscribed = self.object.contactmailingstatus_set.filter(status=ContactMailingStatus.UNSUBSCRIPTION).count() + no_data = self.object.contactmailingstatus_set.filter(status=ContactMailingStatus.ANNOUNCE_NO_DATA).count() + links = self.object.contactmailingstatus_set.filter(status=ContactMailingStatus.LINK_OPENED).count() + CMS = ContactMailingStatus + opened_percent = 0 if opened or sent == 0 else (float(opened)/sent)*100 + unsub_percent = 0 if unsubscribed or sent == 0 else (float(unsubscribed)/sent)*100 + stat = { + 'sent':{'data':sent, 'filter':""}, + 'errors':{ 'data':errors, 'filter':CMS.ERROR}, + 'opened':{'data': opened, 'filter': CMS.OPENED, 'percent': opened_percent}, + 'unsub':{'data': unsubscribed, 'filter': CMS.UNSUBSCRIPTION, 'percent': unsub_percent}, + 'no_data':{'data': no_data, 'filter': CMS.ANNOUNCE_NO_DATA}, + 'links':{'data': links, 'filter': CMS.LINK_OPENED}} + context.update({'stat': stat}) + return context + + class ExportContacts(FormView): form_class = ContactFilterForm diff --git a/functions/forms.py b/functions/forms.py index e011dda3..cb19d3f5 100644 --- a/functions/forms.py +++ b/functions/forms.py @@ -97,10 +97,10 @@ class TranslatableModelForm(forms.ModelForm): if field.name not in veto_fields} for code, name in settings.LANGUAGES: - # todo: fix requirements - where field is required default language must be required to) for tr_field in self.translatable_fields: field = fkwargs[tr_field].formfield() - field.required = False + if code != get_language(): + field.required = False self.fields[tr_field+"_"+code] = field def clean(self): @@ -126,14 +126,13 @@ class TranslatableModelForm(forms.ModelForm): translations = {obj.language_code: obj for obj in list(inst.translations.all())} for lang in self.data_by_lang: if lang is not init_lang: - try: - tr = translations[lang] - except KeyError: - # there are no available translation in db - tr = inst.translate(lang) + translation = translations.get(lang) + # there are no available translation in db + if not translation: + translation = inst.translate(lang) for key, value in self.data_by_lang[lang].iteritems(): - setattr(tr, key, value) - tr.save() + setattr(translation, key, value) + translation.save() self.instance = inst.lazy_translation_getter(init_lang) return self.instance diff --git a/templates/admin/newsletters/newsletter_history.html b/templates/admin/newsletters/newsletter_history.html index f024ef90..f9a64245 100644 --- a/templates/admin/newsletters/newsletter_history.html +++ b/templates/admin/newsletters/newsletter_history.html @@ -11,6 +11,7 @@
+
+ {% include 'client/includes/accounts/calendar_list.html' with events=events %} @@ -35,8 +39,8 @@
{% trans 'Все / выделенные:' %}