You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

578 lines
20 KiB

# -*- coding: utf-8 -*-
import datetime
import csv
from django.conf import settings
from django.core.urlresolvers import reverse_lazy, reverse
from django.contrib.sites.models import Site
from django.forms.formsets import formset_factory
from django.forms.models import modelformset_factory
from django.http import Http404, HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.core.files.storage import default_storage
from django.utils import translation
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from django.views.generic import (
CreateView,
DeleteView,
DetailView,
FormView,
ListView,
RedirectView,
UpdateView
)
from emencia.django.newsletter.admin_forms import (
AttachmentForm,
ContactSettingsForm,
MailingListForm,
NewsletterForm,
NewsletterDailyForm,
NewsletterRecommendForm,
NewsletterFilterForm
)
from emencia.django.newsletter.forms import (
MailingStatusFilter,
PopupCountFilter
)
from emencia.django.newsletter.mailer import Mailer
from emencia.django.newsletter.models import (
Attachment,
Contact,
ContactMailingStatus,
ContactSettings,
MailingList,
Newsletter,
NewsletterRecommend
)
from functions.admin_views import paginate_results, AdminListView
from functions.custom_views import ContextMixin, CreateUpdateView
from functions.http import JsonResponse
from HTMLParser import HTMLParseError
from theme.models import Theme
from ..forms import (
ContactFilterForm, ContactImportForm, AutomaticEmailTestForm
)
from ..models import PopupCount
from ..utils.excel import ExcelResponse
from ..utils.tokens import tokenize
class AutomaticEmailTest(ContextMixin, FormView):
form_class = AutomaticEmailTestForm
template_name = 'newsletter/AutomaticEmail_test.html'
# success_url = reverse_lazy('automaticemailtest')
def get_initial(self):
initial = super(AutomaticEmailTest, self).get_initial()
if self.request.GET.get('date'):
initial['date'] = self.request.GET.get('date')
return initial
def form_valid(self, form):
contact = Contact.objects.get(email=form.cleaned_data.get('email'))
uidb36, token = tokenize(contact)
try:
self.extra_ctx.update({
'newsletter': Newsletter.objects.get(sending_date=form.cleaned_data.get('date'))
})
except (Newsletter.DoesNotExist, ) as e:
pass
self.extra_ctx.update({
'contact': contact,
'domain': Site.objects.get_current().domain,
# 'newsletter': self.newsletter,
# 'tracking_image_format': TRACKING_IMAGE_FORMAT,
'uidb36': uidb36, 'token': token,
'name': contact.first_name or contact.last_name or _(u'Подписчик'),
'no_logo_image': default_storage.open('newsletter/images/no-logo.png'),
})
self.extra_ctx.update(contact.get_announce_context_v2(date=form.cleaned_data.get('date')))
return self.form_invalid(form)
class ContactList(FormView):
paginate_by = settings.ADMIN_PAGINATION
model = Contact
template_name = 'c_admin/newsletters/contact_list.html'
form_class = ContactFilterForm
queryset = Contact.objects.all()
def get_form(self, form_class):
if self.request.GET:
return form_class(self.request.GET)
else:
return form_class(**self.get_form_kwargs())
def get(self, request, *args, **kwargs):
if request.GET:
form_class = self.get_form_class()
form = self.get_form(form_class)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
else:
return super(ContactList, self).get(request, *args, **kwargs)
def form_valid(self, form):
qs, _ = form.filter()
result = paginate_results(qs, page=self.request.GET.get('page'))
context = self.get_context_data(form=form)
context.update({'object_list': result})
return self.render_to_response(context)
def get_context_data(self, **kwargs):
context = super(ContactList, self).get_context_data(**kwargs)
qs = self.model.objects.all()
result = paginate_results(qs, page=self.request.GET.get('page'))
context['object_list'] = result
return context
class ContactQueryDelete(RedirectView):
url = reverse_lazy('newsletters_contact_list')
filter_form = ContactFilterForm
def get(self, request, *args, **kwargs):
form = self.filter_form(request.GET)
if form.is_valid():
qs,_ = form.filter()
qs.delete()
return HttpResponseRedirect(self.url)
else:
return HttpResponse('400')
class DeleteContact(DeleteView):
model = Contact
success_url = reverse_lazy('newsletters_contact_list')
template_name = 'c_admin/newsletters/confirm_delete.html'
class UpdateContact(UpdateView):
model = ContactSettings
form_class = ContactSettingsForm
template_name = 'c_admin/newsletters/contact.html'
success_url = '/admin/newsletters/contact/all/'
def form_valid(self, form):
self.object = form.save()
self.object.theme = form.cleaned_data['theme']
self.object.country = form.cleaned_data['country']
self.object.area = form.cleaned_data['area']
self.object.city = form.cleaned_data['city']
self.object.save()
return HttpResponseRedirect(self.get_success_url())
def get_initial(self):
lang = translation.get_language()
obj = self.object.contact
data = self.initial.copy()
city = ','.join(['%s:%s'%(item.id, item.name) for item in self.object.city.filter(translations__language_code=lang)])
data.update({'first_name': obj.first_name, 'subscriber': obj.subscriber,
'valid': obj.valid, 'tester': obj.tester, 'city':city})
return data
class ExportContacts(FormView):
form_class = ContactFilterForm
def get(self, request=None, *args, **kwargs):
form = self.form_class(request.GET)
if form.is_valid():
qs, title = form.filter()
if qs.count():
columns = ('email', 'first_name')
return ExcelResponse(request, qs, title, columns,'contacts')
return HttpResponseRedirect(self.request.META['HTTP_REFERER'])
class ImportContacts(FormView):
form_class = ContactImportForm
success_url = reverse_lazy("newsletters_contact_list")
template_name = 'c_admin/import templates/import_contacts.html'
def form_valid(self, form):
form.save()
return HttpResponseRedirect(self.get_success_url())
class MailingListView(ListView):
paginate_by = settings.ADMIN_PAGINATION
model = MailingList
template_name = 'c_admin/newsletters/mailing_list.html'
class DeleteMailingList(DeleteView):
model = MailingList
template_name = 'c_admin/newsletters/confirm_delete.html'
success_url = reverse_lazy('newsletters_mailinglist')
class MailingListMixin(object):
model = MailingList
form_class = MailingListForm
template_name = 'c_admin/newsletters/mailing_list_object.html'
success_url = '/admin/newsletters/mailinglist/all/'
def dispatch(self, request, *args, **kwargs):
self.filter = kwargs.get('filter', False)
return super(MailingListMixin, self).dispatch(request, *args, **kwargs)
def form_valid(self, form):
filter_form = ContactFilterForm(self.request.GET)
if not self.object:
contacts = Contact.objects.none()
if self.filter and filter_form.is_valid():
contacts, _ = filter_form.filter()
else:
contacts = self.object.subscribers.all()
obj = form.save()
obj.subscribers = form.get_contact_list(contacts)
return HttpResponseRedirect(self.success_url)
def get_context_data(self, **kwargs):
context = super(MailingListMixin, self).get_context_data(**kwargs)
form = ContactFilterForm(self.request.GET)
context['filter_form'] = form
if form.is_valid():
qs, _ = form.filter()
context['contact_count'] = qs.count()
context['filter_params'] = self.filter
return context
class CreateMailingList(MailingListMixin, CreateView):
pass
class UpdateMailingList(MailingListMixin, UpdateView):
pass
def export_contacts(request, pk):
contacts = Contact.objects.filter(
mailinglist_subscriber__pk=pk
).values(
'email', 'first_name', 'last_name'
)
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="contacts.csv"'
writer = csv.writer(response)
for contact in contacts:
writer.writerow(
[contact['email'], contact['first_name'].encode('utf-8'), contact['last_name'].encode('utf-8')]
)
return response
class DailyMailSuccesUrlMixin(object):
def get_success_url(self):
if self.object.dailymail == True:
return reverse('newsletters_dailymail_list')
return super(DailyMailSuccesUrlMixin, self).get_success_url()
class NewsletterCreate(DailyMailSuccesUrlMixin, CreateView):
model = Newsletter
form_class = NewsletterForm
template_name = 'c_admin/newsletters/newsletter_object.html'
success_url = '/admin/newsletters/newsletters/all/'
def get_formset(self):
AttachmentFormSet = formset_factory(AttachmentForm)
if self.request.POST:
return AttachmentFormSet(self.request.POST, self.request.FILES)
else:
return AttachmentFormSet()
def get_context_data(self, **kwargs):
context = super(NewsletterCreate, self).get_context_data(**kwargs)
context['attachment_formset'] = self.get_formset()
return context
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:
if item.is_valid() and item.has_changed():
instance = item.save(commit=False)
instance.newsletter = self.object
instance.save()
return HttpResponseRedirect(self.success_url)
class NewsletterUpdate(DailyMailSuccesUrlMixin, UpdateView):
model = Newsletter
form_class = NewsletterForm
form_class_daily = NewsletterDailyForm
template_name = 'c_admin/newsletters/newsletter_object.html'
template_name_daily = 'c_admin/newsletters/newsletter_object_daily.html'
success_url = '/admin/newsletters/newsletters/all/'
def get_template_names(self):
if self.kwargs.get('dailymail', False):
return [self.template_name_daily]
return super(NewsletterUpdate, self).get_template_names()
def get_form_class(self):
if self.kwargs.get('dailymail', False):
return self.form_class_daily
return super(NewsletterUpdate, self).get_form_class()
def get_formset(self):
if self.request.POST:
AttachmentFormSet = modelformset_factory(Attachment, form=AttachmentForm, exclude=('newsletter',))
else:
AttachmentFormSet = modelformset_factory(Attachment, form=AttachmentForm, exclude=('newsletter',))
if self.request.POST:
return AttachmentFormSet(self.request.POST, self.request.FILES, queryset=self.object.attachment_set.all())
else:
return AttachmentFormSet(queryset=self.object.attachment_set.all())
def get_context_data(self, **kwargs):
context = super(NewsletterUpdate, self).get_context_data(**kwargs)
context['attachment_formset'] = self.get_formset()
return context
def form_valid(self, form):
self.object = form.save()
self.object.test_contacts = form.cleaned_data['test_contacts']
if not self.kwargs.get('dailymail', False):
formset = self.get_formset()
if formset.is_valid():
for item in formset.forms:
if item.is_valid() and item.has_changed():
instance = item.save(commit=False)
instance.newsletter = self.object
instance.save()
return HttpResponseRedirect(self.get_success_url())
class NewsletterListView(AdminListView):
paginate_by = settings.ADMIN_PAGINATION
model = Newsletter
template_name = 'c_admin/newsletters/newsletter_list.html'
template_name_daily = 'c_admin/newsletters/newsletter_list_daily.html'
form_class = NewsletterFilterForm
def get_template_names(self):
if self.kwargs.get('dailymail', False):
return [self.template_name_daily]
return super(NewsletterListView, self).get_template_names()
def get_queryset(self):
return self.model.objects.filter(
dailymail=self.kwargs.get('dailymail', False)
)
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'Нет тестовых контактов'))
if newsletter.dailymail == False:
redirect = request.META.get('HTTP_REFERER', '/admin/newsletter/newsletter/all/')
else:
redirect = request.META.get('HTTP_REFERER', reverse('newsletters_dailymail_list'))
return HttpResponseRedirect(redirect)
class NewsletterStatistics(DetailView):
model = Newsletter
template_name = 'c_admin/newsletters/newsletter_stat.html'
def get_context_data(self, **kwargs):
context = super(NewsletterStatistics, self).get_context_data(**kwargs)
if self.object.ab_testing:
context.update({'stat': self.get_stat_data(params={'ab': Newsletter.A})})
context.update({'statB': self.get_stat_data(params={'ab': Newsletter.B})})
else:
context.update({'stat': self.get_stat_data()})
return context
def get_stat_data(self, params={}):
qs = self.object.contactmailingstatus_set
sent = qs.filter(status=ContactMailingStatus.SENT, **params).count()
errors = qs.filter(status=ContactMailingStatus.ERROR, **params).count()
_opened_qs = qs.filter(status=ContactMailingStatus.OPENED, **params).\
values_list('contact', flat=True)
opened = _opened_qs.distinct().count()
opened_all = _opened_qs.count()
unsubscribed = qs.filter(status=ContactMailingStatus.UNSUBSCRIPTION, **params).\
values_list('contact', flat=True).distinct().count()
no_data = qs.filter(status=ContactMailingStatus.ANNOUNCE_NO_DATA, **params).count()
links = qs.filter(status=ContactMailingStatus.LINK_OPENED, **params).count()
links_unique = qs.filter(status=ContactMailingStatus.LINK_OPENED, **params).\
values_list('contact', flat=True).distinct().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
ab = params.get('ab', '')
stat = {
'sent': {'data': sent, 'filter': ""},
'errors': {'data': errors, 'filter': CMS.ERROR},
'opened': {'data': opened, 'data_all': opened_all, '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},
'links_unique': {'data': links_unique, 'filter': CMS.LINK_OPENED},
'ab': ab,
}
return stat
class DailyMailSuccesUrlMixinUrl(object):
def get_url(self, newsletter):
if newsletter.dailymail == True:
return reverse('newsletters_dailymail_list')
return self.url
class NewsletterCloneView(RedirectView, DailyMailSuccesUrlMixinUrl):
url = reverse_lazy("newsletters_newsletters_list")
def get(self, request, *args, **kwargs):
newsletter = get_object_or_404(Newsletter, id=kwargs['pk'])
newsletter.clone()
return HttpResponseRedirect(self.get_url(newsletter))
def post(self, request, *args, **kwargs):
return self.get(request, *args, **kwargs)
class NewsletterCancelView(NewsletterCloneView, DailyMailSuccesUrlMixinUrl):
url = reverse_lazy("newsletters_newsletters_list")
def get(self, request, *args, **kwargs):
newsletter = get_object_or_404(Newsletter, id=kwargs['pk'])
if newsletter.can_cancel:
newsletter.status = Newsletter.CANCELED
newsletter.save()
return HttpResponseRedirect(self.get_url(newsletter))
class NewsletterHistory(ListView):
model = ContactMailingStatus
template_name = 'c_admin/newsletters/newsletter_history.html'
paginate_by = 50
def get_queryset(self):
self.newsletter = get_object_or_404(Newsletter, pk=self.kwargs['pk'])
if self.request.GET:
form = MailingStatusFilter(self.request.GET)
if form.is_valid():
qs = form.filter(self.newsletter)
else:
qs = ContactMailingStatus.objects.select_related().filter(newsletter=self.newsletter)
else:
qs = ContactMailingStatus.objects.select_related().filter(newsletter=self.newsletter)
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
form = MailingStatusFilter(self.request.GET)
context['filter_form'] = form
return context
class NewsletterDelete(DailyMailSuccesUrlMixin, DeleteView):
model = Newsletter
template_name = 'c_admin/newsletters/confirm_delete.html'
success_url = reverse_lazy('newsletters_newsletters_list')
def count_popups(request):
if not request.is_ajax():
return HttpResponse("request is not ajax")
else:
themes = request.GET.getlist('theme')
if themes:
for theme_id in themes:
obj,_ = PopupCount.objects.get_or_create(theme=Theme.objects.get(id=theme_id), date=datetime.date.today())
obj.cnt += 1
obj.save()
else:
obj,_ = PopupCount.objects.get_or_create(theme=None, date=datetime.date.today())
obj.cnt+=1
obj.save()
return HttpResponse(obj.cnt, content_type='application/json')
class PopupStatisticsView(FormView):
form_class = PopupCountFilter
template_name = 'c_admin/newsletters/popup_count.html'
def get(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = form_class(request.GET)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
data = form.filter()
data['form'] = form
return self.render_to_response(data)
def theme_for_filter_ajax(request):
if request.is_ajax():
empty = [{'pk': '', 'name': '-----'}]
try:
ml = MailingList.objects.get(pk=request.GET.get('id'))
themes = Theme.objects.language().filter(pk__in=[x.pk for x in ml.theme_for_filter.all()]).values('pk', 'name')
return JsonResponse({'data': empty + [{'pk': x['pk'], 'name': force_text(x['name'])} for x in themes]})
except (MailingList.DoesNotExist, ValueError, ):
return JsonResponse({'data': empty})
return Http404()
class RecommendsList(ListView):
model = NewsletterRecommend
template_name = 'newsletter/recommend/list.html'
class RecommendsCreateorEdit(CreateUpdateView):
model = NewsletterRecommend
form_class = NewsletterRecommendForm
template_name = 'newsletter/recommend/create.html'
success_url = reverse_lazy('newsletters_recommends_list')
class RecommendsDelete(DeleteView):
model = NewsletterRecommend
template_name = 'newsletters/confirm_delete.html'
success_url = reverse_lazy('newsletters_recommends_list')