Merge branch 'newsletter' of git.general-servers.com:expomap/expomap into newsletter

remotes/origin/1203
Nazar Kotjuk 10 years ago
commit b6de05dc0e
  1. 4
      core/utils.py
  2. 21
      core/views.py
  3. 10
      emencia/django/newsletter/admin_urls.py
  4. 10
      emencia/django/newsletter/models.py
  5. 49
      emencia/django/newsletter/views/admin_views.py
  6. 17
      functions/forms.py
  7. BIN
      static/img/announce-letter.png
  8. 58
      templates/admin/newsletters/newsletter_history.html
  9. 4
      templates/admin/newsletters/newsletter_list.html
  10. 62
      templates/admin/newsletters/newsletter_stat.html
  11. 22
      templates/client/accounts/calendar.html
  12. 17
      templates/client/includes/announces.html
  13. BIN
      templates/client/static_client/img/announce-letter.png

@ -83,13 +83,13 @@ def queryset_to_workbook(queryset, columns, report_date = None):
'pattern: pattern solid, fore_color gray_ega;',
)
odd_style = xlwt.Style.easyxf(
'font: name Calibri, height 300, bold False;'
'font: name Calibri, height 240, bold False;'
'borders: left thin, right thin, top thin, bottom thin;'
'alignment: horizontal center, vertical center, wrap True;'
'pattern: pattern solid, fore_color white;',
)
even_style = xlwt.Style.easyxf(
'font: name Calibri, height 300, bold False;'
'font: name Calibri, height 240, bold False;'
'borders: left thin, right thin, top thin, bottom thin;'
'alignment: horizontal center, vertical center, wrap True;'
'pattern: pattern solid, fore_color silver_ega;',

@ -266,13 +266,18 @@ def download_workbook(request):
lang = get_language()
data = request.GET
if data:
qs = []
for i,obj in enumerate(data):
if data.get('data[%i][name]' % i) == 'expo':
qs.append(Exposition.objects.language(lang).get(id=data['data[%i][value]'%i]))
elif data.get('data[%i][name]' % i) == 'conf':
qs.append(Conference.objects.language(lang).get(id=data['data[%i][value]'%i]))
if data.get('filter') == u'future':
qs = request.user.calendar.get_events()
qs = [event for event in qs if event.data_begin > datetime.date.today()]
else:
qs = []
for i,obj in enumerate(data):
if data.get('data[%i][name]' % i) == 'expo':
qs.append(Exposition.objects.language(lang).get(id=data['data[%i][value]'%i]))
elif data.get('data[%i][name]' % i) == 'conf':
qs.append(Conference.objects.language(lang).get(id=data['data[%i][value]'%i]))
if not qs:
return HttpResponseRedirect("/profile/calendar/?message=empty")
earliest_event = qs[0].data_begin
for i, obj in enumerate(qs, start=1):
if obj.data_begin < earliest_event:
@ -305,4 +310,4 @@ def download_workbook(request):
workbook.save(response)
return response
else:
return HttpResponseRedirect(request.META.get('HTTP_REFERER'), "/profile/calendar/")
return HttpResponseRedirect("/profile/calendar/")

@ -2,16 +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
DeleteMailingList, ImportContacts, NewsletterHistory, NewsletterStatistics
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/',
url(r'^newsletters/(?P<pk>\d+)/edit/$', NewsletterUpdate.as_view(), name='newsletters_newsletters_update'),
url(r'^newsletters/(?P<pk>\d+)/history/', NewsletterHistory.as_view(), name='newsletters_newsletters_history'),
url(r'^newsletters/(?P<pk>\d+)/statistics/', NewsletterStatistics.as_view(), name='newsletters_newsletters_stat'),
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'^newsletters/$', NewsletterCreate.as_view(), name='newsletters_newsletters_create'),
url(r'^mailinglist/all/$', MailingListView.as_view(), name='newsletters_mailinglist'),

@ -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 +=": <a href='%s'>%s</a>"% (self.link.url, self.link.url)
return verbose
def __unicode__(self):
return '%s : %s : %s' % (self.newsletter.__unicode__(),
self.contact.__unicode__(),

@ -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 _
@ -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,51 @@ 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 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

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

@ -0,0 +1,58 @@
{% extends 'admin/base.html' %}
{% load staticfiles %}
{% block body %}
<div class="box span10">
<div class="box-header well">
<h2><i class="icon-arrow-down"></i>История для {{ newsletter.title }}</h2>
</div>
<div class="box-content">
<form id="id_form" class="form-inline">
<div class="form-group">
<select class="form-control" name="filter" id="filter">
<option>Фильтровать</option>
<option value="">Все</option>
{% for id, name in choices%}
<option class="opt" value="{{ id }}">{{ name }}</option>
{% endfor %}
</select>
</div>
</form>
<table class="table table-hover table table-bordered table-striped">
<colgroup>
<col width="33%">
<col width="33%">
<col width="33%">
</colgroup>
<thead>
<tr>
<th>Дата</th>
<th>Контакт</th>
<th>Статус</th>
</tr>
</thead>
<tbody>
{% for item in object_list %}
<tr>
<td>{{ item.creation_date|date:"Y-m-d H:i:s" }}</td>
<td>{{ item.contact.email }}</td>
<td>{{ item.get_verbose_status|safe }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{# pagination #}
{% include 'admin/includes/admin_pagination.html' with page_obj=object_list %}
</div>
<script>
$(document).ready(function(){
$("#filter").on('change', function(event){
console.log("click");
$("#id_form").submit();
})
})
</script>
{% endblock %}

@ -31,8 +31,8 @@
<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>
<td><a href="#">История</a> </td>
<td>{% if item.status == item.SENT or item.status == item.CANCELED %}<a href="#">Статистика</a>{% endif %}</td>
<td><a href="{% url 'newsletters_newsletters_history' item.id %}">История</a> </td>
<td>{% if item.status == item.SENT or item.status == item.CANCELED %}<a href="{% url 'newsletters_newsletters_stat' item.id %}">Статистика</a>{% endif %}</td>
</tr>
{% endfor %}
</tbody>

@ -0,0 +1,62 @@
{% extends 'admin/base.html' %}
{% load staticfiles %}
{% block body %}
<div class="box span10">
<div class="box-header well">
<h2><i class="icon-arrow-down"></i>Статистика для {{ newsletter.title }}</h2>
</div>
<div class="box-content">
<table class="table table-hover table table-bordered table-striped">
<colgroup>
<col width="45%">
<col width="45%">
<col width="10%">
</colgroup>
<thead>
<tr>
<th>Название</th>
<th>Количество писем</th>
<th>&nbsp</th>
</tr>
</thead>
<tbody>
<tr>
<td>Отправлено</td>
<td>{{ stat.sent.data }}</td>
<td><a href="{% url 'newsletters_newsletters_history' object.id %}?filter={{ stat.sent.filter }}">Подробно</a></td>
</tr>
<tr>
<td>Ошибок</td>
<td>{{ stat.errors.data }}</td>
<td><a href="{% url 'newsletters_newsletters_history' object.id %}?filter={{ stat.errors.filter }}">Подробно</a></td>
</tr>
<tr>
<td>Открыто</td>
<td>{{ stat.opened.data }} {% if stat.opened.percent %} ({{ stat.opened.percent|floatformat:"0" }}%) {% endif %}</td>
<td><a href="{% url 'newsletters_newsletters_history' object.id %}?filter={{ stat.opened.filter }}">Подробно</a></td>
</tr>
<tr>
<td>Отписалось</td>
<td>{{ stat.unsub.data }} {% if stat.unsub.percent %} ({{ stat.unsub.percent|floatformat:"0" }}%) {% endif %}</td>
<td><a href="{% url 'newsletters_newsletters_history' object.id %}?filter={{ stat.unsub.filter }}">Подробно</a></td>
</tr>
<tr>
<td>Нет данных</td>
<td>{{ stat.no_data.data }}</td>
<td><a href="{% url 'newsletters_newsletters_history' object.id %}?filter={{ stat.no_data.filter }}">Подробно</a></td>
</tr>
<tr>
<td>Переходов по ссылкам</td>
<td>{{ stat.links.data }}</td>
<td><a href="{% url 'newsletters_newsletters_history' object.id %}?filter={{ stat.links.filter }}">Подробно</a></td>
</tr>
</tbody>
</table>
</div>
</div>
{% endblock %}

@ -20,14 +20,18 @@
{% block content_list %}
<div class="m-article p-calendar">
{% with days=days events=events current_day=current_day %}
{% include 'includes/accounts/calendar_table.html' %}
{% include 'client/includes/accounts/calendar_table.html' %}
{% endwith %}
</div>
<div class="m-article cal-lists">
{% if events|length > 0 %}
<div class="cl-sect">
<div class="cls-title">{{ days.15|date:"F"}}’{{ days.15|date:"y"}}</div>
<div class="cls-title">{{ days.15|date:"F"}}’{{ days.15|date:"y"}}
<div style="float:right;margin-right: 5px;" class="check-wrap">
<label class="check"><input type="checkbox" id="selectall"/></label>
</div>
</div>
{% include 'client/includes/accounts/calendar_list.html' with events=events %}
</div>
@ -35,8 +39,8 @@
<div class="cla-title">{% trans 'Все / выделенные:' %}</div>
<div class="cla-btns">
<a class="button" id="btn_delete" href="#">{% trans 'удалить из расписания' %}</a>
<a id ='export' class="button icon-save" href="#">{% trans 'сохранить в xls' %}</a>
<a id ='export' class="button icon-save" href="#">{% trans 'выбраные в xls' %}</a>
<a id ='future' class="button icon-save" href="#">{% trans 'все предстоящие в xls' %}</a>
<!--<a class="button icon-calendar-o" href="#">{% trans 'ЭКСПОРТИРОВАТЬ В' %} <span class="lc">iCal</span></a>
@ -54,6 +58,16 @@
</div>
<script>
$(function(){
if(window.location.search === "?message=empty"){
alert("{% trans 'У вас нету событий в будущем!' %}");
window.location.search = ""
}
$('#selectall').click(function(event) { //on click
$(".qwer").trigger("click");
});
$("#future").click(function(event) {
window.location.href = "/profile/calendar/export/?" + "filter=future";
});
$("#export").click(function(event){
event.preventDefault();
var list = $('.qwer');

@ -1,12 +1,13 @@
{% load i18n %}
{% load staticfiles %}
<div id="subscribe-sm" class="subscribe-sm">
<header><a href="#" style="text-decoration: none">{% trans 'получать анонсЫ' %}</a></header>
{% comment %}
<ul>
<li><a class="icon-big-email" href="#">{% trans 'по e-mail' %}</a></li>
</ul>
{% endcomment %}
<header>
<a href="#" style="text-decoration: none"> {% trans 'получать анонсЫ' %}
<span>
<img style="margin-right: -2px; margin-bottom: 4px; width: 12%;" src="{% static 'img/announce-letter.png' %}">
</span>
</a>
</header>
</div>
<hr>
<hr/>

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Loading…
Cancel
Save