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.
 
 
 
 
 
 

557 lines
20 KiB

# -*- coding: utf-8 -*-
import os
import datetime
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,
TemplateView,
UpdateView
)
from emencia.django.newsletter.admin_forms import (
AttachmentForm,
ContactSettingsForm,
MailingListForm,
NewsletterForm,
NewsletterDailyForm,
NewsletterRecommendForm,
)
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
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
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(ListView):
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'
success_url = '/admin/newsletters/newsletters/all/'
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):
qs = super(NewsletterListView, self).get_queryset()
return qs.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')