Merge branch 'develop'

remotes/origin/HEAD
Slava Kyrachevsky 9 years ago
commit ffec26d7ba
  1. 1
      README.md
  2. 4
      apps/accounts/urls.py
  3. 48
      apps/accounts/views.py
  4. 2
      apps/conference/forms.py
  5. 33
      apps/emencia/django/newsletter/forms.py
  6. 38
      apps/emencia/django/newsletter/mailer.py
  7. 19
      apps/emencia/django/newsletter/management/commands/send_newsletter.py
  8. 6
      apps/emencia/django/newsletter/models.py
  9. 2
      apps/emencia/django/newsletter/urls/__init__.py
  10. 135
      apps/emencia/django/newsletter/views/expo_views.py
  11. 2
      apps/exposition/admin.py
  12. 2
      apps/exposition/forms.py
  13. 47
      apps/file/admin.py
  14. 41
      apps/file/forms.py
  15. 2
      apps/file/models.py
  16. 2
      apps/import_xls/excel_settings.py
  17. 64
      apps/import_xls/import_forms.py
  18. 48
      apps/import_xls/utils.py
  19. 2
      apps/place_exposition/forms.py
  20. 2
      proj/admin.py
  21. 26
      proj/settings.py
  22. 1
      requirements.txt
  23. 153
      static/custom_js/main.js
  24. 102
      static/custom_js/select_tag.js
  25. 87
      static/mailing_settings/css/main.css
  26. 59
      static/mailing_settings/js/main.js
  27. 192
      templates/c_admin/article/blog_form.html
  28. 34
      templates/c_admin/file/file_update.html
  29. 4
      templates/c_admin/newsletters/contact_list.html
  30. 2
      templates/c_admin/newsletters/newsletter_object.html
  31. 8
      templates/c_admin/place_exposition/place_exposition.html
  32. 215
      templates/client/newsletters/mailing_settings.html
  33. 7
      templates/client/service/participation.html

@ -13,7 +13,6 @@ INSTALLED_APPS += (
) )
RAVEN_CONFIG = { RAVEN_CONFIG = {
'dsn': 'http://474617c96350412d80735900c6717b9a:330285c9034947a181cbae8b52bb15d8@88.198.17.35:9000/3', 'dsn': 'http://474617c96350412d80735900c6717b9a:330285c9034947a181cbae8b52bb15d8@88.198.17.35:9000/3',
'release': raven.fetch_git_sha(os.path.dirname(os.pardir)),
} }
``` ```

@ -8,7 +8,6 @@ from views import (
CalendarView, CalendarView,
Feed, Feed,
HomeView, HomeView,
MailingSettings,
NameView, NameView,
PhoneView, PhoneView,
ProfileCompanyView, ProfileCompanyView,
@ -21,7 +20,6 @@ from views import (
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^profile/company/$', login_required(ProfileCompanyView.as_view())), url(r'^profile/company/$', login_required(ProfileCompanyView.as_view())),
url(r'^profile/mailing/$', MailingSettings.as_view(), name='accounts-mailing_settings'),
url(r'^profile/settings/$', login_required(SettingsView.as_view()), name='accounts_settings'), url(r'^profile/settings/$', login_required(SettingsView.as_view()), name='accounts_settings'),
url(r'^profile/calendar/remove/$', 'accounts.views.remove_from_calendar'), url(r'^profile/calendar/remove/$', 'accounts.views.remove_from_calendar'),
url(r'^profile/calendar/export/$', 'core.views.download_workbook'), url(r'^profile/calendar/export/$', 'core.views.download_workbook'),
@ -44,7 +42,7 @@ urlpatterns = patterns('',
url(r'^profile/change-password/', 'accounts.views.change_password'), url(r'^profile/change-password/', 'accounts.views.change_password'),
url( url(
r'^profile/subscribe-themes-tags/$', r'^profile/subscribe-themes-tags/$',
login_required(UserSubscribeThemesTagsView.as_view()), UserSubscribeThemesTagsView.as_view(),
name='user_subscribe_themes_tags' name='user_subscribe_themes_tags'
), ),

@ -27,7 +27,7 @@ from company.edit_forms import NameForm as CompNameForm, HomeForm as CompHomeFor
EmailForm as CompEmailForm, WebPageForm as CompWebPageForm, SocialForm as CompSocialForm,\ EmailForm as CompEmailForm, WebPageForm as CompWebPageForm, SocialForm as CompSocialForm,\
TagForm as CompTagForm, DescriptionForm as CompDescr, StaffForm as CompStaff, \ TagForm as CompTagForm, DescriptionForm as CompDescr, StaffForm as CompStaff, \
FoundationForm as CompFound, SpecializationForm as CompSpec, AddressForm as CompAddress FoundationForm as CompFound, SpecializationForm as CompSpec, AddressForm as CompAddress
from emencia.django.newsletter.forms import SubscribeSettingsForm, MailingSettingsForm from emencia.django.newsletter.forms import SubscribeSettingsForm
from emencia.django.newsletter.models import Contact, ContactSettings from emencia.django.newsletter.models import Contact, ContactSettings
from .forms import ChangePasswordForm, FeedFilterForm from .forms import ChangePasswordForm, FeedFilterForm
@ -115,41 +115,6 @@ class GetUserMixin(object):
return instance return instance
class MailingSettings(GetUserMixin, ContextMixin, AjaxableResponseMixin, CreateUpdateView):
form_class = MailingSettingsForm
template_name = 'client/newsletters/mailing_settings.html'
success_url = reverse_lazy('accounts-mailing_settings')
def get_success_url(self):
return self.success_url
def get_object(self):
self.extra_ctx.update({
'r_cities': City.used.russia(),
})
instance = self.get_user()
if instance is not None:
self.extra_ctx.update({
'checked_f_countries': list(instance.f_countries.values_list('pk', flat=True)),
'checked_r_cities': list(instance.r_cities.values_list('pk', flat=True)),
'checked_tg': list(instance.tags.values_list('pk', flat=True)),
'checked_th': list(instance.themes.values_list('pk', flat=True)),
'contact': instance,
})
if self.request.GET.get('unsibscribe') and instance.subscriber:
instance.unsubscribe()
self.extra_ctx.update({'unsubscribe_success': True})
elif not instance.subscriber:
self.extra_ctx.update({'unsubscribed': True})
return instance
def form_valid(self, form):
return super(MailingSettings, self).form_valid(form)
def form_invalid(self, form):
return super(MailingSettings, self).form_invalid(form)
class CalendarView(TemplateView): class CalendarView(TemplateView):
""" """
display template with user calendar(one month) display template with user calendar(one month)
@ -578,11 +543,14 @@ class UserSubscribeThemesTagsView(GetUserMixin, TemplateView):
ctx = super(UserSubscribeThemesTagsView, self).get_context_data(**kwargs) ctx = super(UserSubscribeThemesTagsView, self).get_context_data(**kwargs)
data = [] data = []
instance = self.get_user() instance = self.get_user()
user_themes = []
user_tags = []
themes = Theme.objects.language().values('pk', 'name') themes = Theme.objects.language().values('pk', 'name')
user_themes = instance.themes.values_list('pk', flat=True) if instance is not None:
user_tags = instance.tags.values_list('pk', flat=True) user_themes = instance.themes.values_list('pk', flat=True)
user_tags = instance.tags.values_list('pk', flat=True)
for theme in themes: for theme in themes:
tags = [] tags = []
@ -607,4 +575,6 @@ class UserSubscribeThemesTagsView(GetUserMixin, TemplateView):
def render_to_response(self, context, **response_kwargs): def render_to_response(self, context, **response_kwargs):
context.pop('view') context.pop('view')
return HttpResponse(json.dumps(context), content_type=self.content_type) return HttpResponse(
json.dumps(context), content_type=self.content_type
)

@ -56,7 +56,7 @@ class ConferenceCreateForm(forms.Form):
#organiser = forms.MultipleChoiceField(label=u'Организаторы', required=False, #organiser = forms.MultipleChoiceField(label=u'Организаторы', required=False,
# choices=[(item.id, item.name) for item in Organiser.objects.language().all()]) # choices=[(item.id, item.name) for item in Organiser.objects.language().all()])
org = forms.CharField(required=False, label=_(u'Организатор')) org = forms.CharField(required=False, label=_(u'Организатор'))
country = forms.ChoiceField(label=_(u'Страна'), choices=[(c.id, c.name) for c in Country.objects.language().all()]) country = forms.ChoiceField(label=_(u'Страна'), choices=list(set([(c.id, c.name) for c in Country.objects.language().all()])))
theme = forms.MultipleChoiceField(label=_(u'Тематики'), theme = forms.MultipleChoiceField(label=_(u'Тематики'),
choices=[(item.id, item.name) for item in Theme.objects.language().all()]) choices=[(item.id, item.name) for item in Theme.objects.language().all()])

@ -81,6 +81,12 @@ class MailingListSubscriptionForm(forms.ModelForm):
class MailingSettingsForm(forms.ModelForm): class MailingSettingsForm(forms.ModelForm):
email = forms.EmailField(
error_messages={
'required': _(u'Поле e-mail обязательно для заполнения')
},
widget=forms.TextInput(attrs={'placeholder': _(u'Ваш e-mail')})
)
r_cities = ML_ModelMultipleChoiceField( r_cities = ML_ModelMultipleChoiceField(
label=_(u'Города России'), required=False, label=_(u'Города России'), required=False,
queryset=City.objects.all()) queryset=City.objects.all())
@ -100,11 +106,12 @@ class MailingSettingsForm(forms.ModelForm):
class Meta: class Meta:
model = Contact model = Contact
fields = [ fields = [
'moscow', 'russia', 'r_cities', 'foreign', 'email', 'first_name', 'moscow', 'russia', 'r_cities', 'foreign',
'periodic', 'periodic_day', 'content_news', 'content_overview', 'periodic', 'periodic_day', 'content_news', 'content_overview',
'content_articles', 'content_articles',
] ]
widgets = { widgets = {
'first_name': forms.TextInput(attrs={'placeholder': _(u'Ваше имя')}),
'moscow': forms.CheckboxInput(), 'moscow': forms.CheckboxInput(),
'foreign': forms.CheckboxInput(), 'foreign': forms.CheckboxInput(),
'periodic': forms.RadioSelect(), 'periodic': forms.RadioSelect(),
@ -119,6 +126,10 @@ class MailingSettingsForm(forms.ModelForm):
for field in ['co', 'r_cities', 'tg', 'th', 'area']: for field in ['co', 'r_cities', 'tg', 'th', 'area']:
self.fields[field].widget.attrs.update({'style': 'display: none;'}) self.fields[field].widget.attrs.update({'style': 'display: none;'})
if self.instance and self.instance.pk: if self.instance and self.instance.pk:
# если пользовать авторизован, у нас есть инстанс
# и там не нужно выводить для редактирования его личные данные
del self.fields['email']
del self.fields['first_name']
# area # area
self.initial['area'] = set(self.instance.area.values_list('pk', flat=True)) self.initial['area'] = set(self.instance.area.values_list('pk', flat=True))
area_q = Area.objects.language().all().order_by('name') area_q = Area.objects.language().all().order_by('name')
@ -184,6 +195,19 @@ class MailingSettingsForm(forms.ModelForm):
obj.save() obj.save()
return obj return obj
def clean(self):
cleaned_data = super(MailingSettingsForm, self).clean()
if not cleaned_data.get('tg') and not cleaned_data.get('th'):
raise forms.ValidationError(_(u'Для успешной подписки необходимо '
u'выбрать тематики событий, которые '
u'вам интересны. На основе этих '
u'настроек мы включим в ваше письмо '
u'релевантные события!'))
if not cleaned_data.get('moscow') and not cleaned_data.get('russia') and not cleaned_data.get('foreign') and not cleaned_data.get('area') and not cleaned_data.get('r_cities') and not cleaned_data.get('co'):
raise forms.ValidationError(_(u'Необходимо выбрать минимум '
u'1 вариант в гео-фильтрах'))
return cleaned_data
class AllMailingListSubscriptionForm(MailingListSubscriptionForm): class AllMailingListSubscriptionForm(MailingListSubscriptionForm):
"""Form for subscribing to all mailing list""" """Form for subscribing to all mailing list"""
@ -221,9 +245,10 @@ class ContactForm(forms.ModelForm):
def clean_email(self): def clean_email(self):
email = self.cleaned_data['email'] email = self.cleaned_data['email']
try: try:
self.instance = Contact.objects.get(email__iexact=email) Contact.objects.get(email__iexact=email)
return email raise forms.ValidationError(_(u'Указанный e-mail адрес уже '
except (Contact.DoesNotExist, ): u'подписан на рассылку'))
except Contact.DoesNotExist:
pass pass
return email return email

@ -41,6 +41,7 @@ from django.template.loader import render_to_string, get_template
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
from django.utils.encoding import smart_unicode from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from django.utils import timezone
from django.core.files.storage import default_storage from django.core.files.storage import default_storage
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.exceptions import SuspiciousOperation from django.core.exceptions import SuspiciousOperation
@ -167,7 +168,13 @@ class NewsLetterSender(object):
all the attached files. all the attached files.
""" """
content_html = self.build_email_content(contact, announce_context, name) content_html = self.build_email_content(contact, announce_context)
if '{name}' in content_html:
content_html = content_html.format(
**{
'name': name or contact.first_name or contact.last_name or _(u'Подписчик')
}
)
h = HTMLParser.HTMLParser() h = HTMLParser.HTMLParser()
content_html = h.unescape(content_html) content_html = h.unescape(content_html)
@ -344,7 +351,6 @@ class NewsLetterSender(object):
logo_path = default_storage.path('newsletter/images/no-logo.png') logo_path = default_storage.path('newsletter/images/no-logo.png')
elif logo and not logo_path: elif logo and not logo_path:
logo_path = logo.path logo_path = logo.path
print(logo, logo_path, obj)
try: try:
ctype, encoding = mimetypes.guess_type(logo_path) ctype, encoding = mimetypes.guess_type(logo_path)
@ -392,7 +398,7 @@ class NewsLetterSender(object):
title = self.newsletter.title2.format(**self.preheader_ctx) title = self.newsletter.title2.format(**self.preheader_ctx)
return title return title
def build_email_content(self, contact, announce_context=None, name=None): def build_email_content(self, contact, announce_context=None):
"""Generate the mail for a contact""" """Generate the mail for a contact"""
uidb36, token = tokenize(contact) uidb36, token = tokenize(contact)
context = Context({'contact': contact, context = Context({'contact': contact,
@ -400,7 +406,6 @@ class NewsLetterSender(object):
'newsletter': self.newsletter, 'newsletter': self.newsletter,
'tracking_image_format': TRACKING_IMAGE_FORMAT, 'tracking_image_format': TRACKING_IMAGE_FORMAT,
'uidb36': uidb36, 'token': token, 'uidb36': uidb36, 'token': token,
'name': name or contact.first_name or contact.last_name or _(u'Подписчик'),
'settings_links': self.settings_links, 'settings_links': self.settings_links,
}) })
if self.announce: if self.announce:
@ -642,16 +647,18 @@ class Mailer(NewsLetterSender):
expedition_list = self.expedition_list expedition_list = self.expedition_list
number_of_recipients = len(expedition_list) # number_of_recipients = len(expedition_list)
if self.verbose: # if self.verbose:
print '%i emails will be sent' % number_of_recipients # print '%i emails will be sent' % number_of_recipients
i = 1 # FIXME: Временно сделана отправка только 1 письма.
for contact in expedition_list: # См FIXME в команде send_newsletter
for i, contact in enumerate(expedition_list, 1):
print 'sending to contact: %s, %s (%s)' % (contact.pk, contact.email, timezone.now())
send = True send = True
if self.verbose: # if self.verbose:
print '- Processing %s/%s (%s)' % ( # print '- Processing %s/%s (%s)' % (
i, number_of_recipients, contact.pk) # i, number_of_recipients, contact.pk)
# #
self.build_preheader_ctx(contact) self.build_preheader_ctx(contact)
@ -693,8 +700,6 @@ class Mailer(NewsLetterSender):
self.smtp.quit() self.smtp.quit()
self.smtp_connect() self.smtp_connect()
i += 1
# маркируем оставшиеся контакты на второй этап # маркируем оставшиеся контакты на второй этап
self.mark_contacts_for_second_stage() self.mark_contacts_for_second_stage()
@ -716,10 +721,13 @@ class Mailer(NewsLetterSender):
return [] return []
if self.newsletter.dailymail and not self.test: if self.newsletter.dailymail and not self.test:
return self.newsletter.get_dailymail_subscribers() # FIXME: врменно добавил жёсткий срез для отправки 1 письма
return self.newsletter.get_dailymail_subscribers()[:1]
qs = super(Mailer, self).expedition_list qs = super(Mailer, self).expedition_list
# FIXME: врменно добавил жёсткий срез для отправки 1 письма
self.credits = 1
qs = qs[:self.credits] qs = qs[:self.credits]
if self.test: if self.test:

@ -1,9 +1,11 @@
# -*- coding: utf-8 -*-
"""Command for sending the newsletter""" """Command for sending the newsletter"""
from datetime import datetime, timedelta from datetime import datetime, timedelta
from time import sleep from time import sleep
from django.conf import settings from django.conf import settings
from django.utils.translation import activate from django.utils.translation import activate
from django.utils import timezone
from django.core.management.base import NoArgsCommand from django.core.management.base import NoArgsCommand
from emencia.django.newsletter.settings import SEND_HOUR_LOOP from emencia.django.newsletter.settings import SEND_HOUR_LOOP
@ -20,14 +22,17 @@ class Command(NoArgsCommand):
self.verbose = int(options['verbosity']) self.verbose = int(options['verbosity'])
activate(settings.LANGUAGE_CODE) activate(settings.LANGUAGE_CODE)
if SEND_HOUR_LOOP: # FIXME: временно делаем одну отправку и завершаем.
while self.end_time > datetime.now(): # Это сделано для того, чтобы отправка писем была более контролируемая
self.send() self.send()
sleep(30) # if SEND_HOUR_LOOP:
else: # while self.end_time > datetime.now():
self.send() # self.send()
# sleep(30)
# else:
# self.send()
if self.verbose: if self.verbose:
print 'End session sending' print 'End session sending (%s)' % timezone.now()
def send(self): def send(self):
for newsletter in Newsletter.objects.exclude( for newsletter in Newsletter.objects.exclude(

@ -157,10 +157,10 @@ class Contact(models.Model):
from_users = models.BooleanField(default=False) from_users = models.BooleanField(default=False)
dailymailing = models.BooleanField(default=False) dailymailing = models.BooleanField(default=False)
moscow = models.BooleanField(_(u'Москва'), blank=True, default=True) moscow = models.BooleanField(_(u'Москва'), blank=True, default=False)
russia = models.BooleanField(_(u'Россия'), blank=True, default=True) russia = models.BooleanField(_(u'Россия'), blank=True, default=False)
r_cities = models.ManyToManyField('city.City', blank=True, null=True, verbose_name=_(u'Города России')) r_cities = models.ManyToManyField('city.City', blank=True, null=True, verbose_name=_(u'Города России'))
foreign = models.BooleanField(_(u'Зарубеж'), blank=True, default=True) foreign = models.BooleanField(_(u'Зарубеж'), blank=True, default=False)
f_countries = models.ManyToManyField('country.Country', blank=True, null=True, verbose_name=_(u'Зарубежные страны')) f_countries = models.ManyToManyField('country.Country', blank=True, null=True, verbose_name=_(u'Зарубежные страны'))
area = models.ManyToManyField('country.Area', blank=True, null=True, verbose_name=_(u'Географическая зона')) area = models.ManyToManyField('country.Area', blank=True, null=True, verbose_name=_(u'Географическая зона'))
periodic = models.PositiveSmallIntegerField(_(u'Периодичность отправки'), periodic = models.PositiveSmallIntegerField(_(u'Периодичность отправки'),

@ -12,7 +12,7 @@ urlpatterns = patterns('',
url(r'^statistics/', include('emencia.django.newsletter.urls.statistics')), url(r'^statistics/', include('emencia.django.newsletter.urls.statistics')),
url(r'^', include('emencia.django.newsletter.urls.newsletter')), url(r'^', include('emencia.django.newsletter.urls.newsletter')),
url(r'^test-letter/', TemplateView.as_view(template_name='client/newsletters/announce_template.html')), url(r'^test-letter/', TemplateView.as_view(template_name='client/newsletters/announce_template.html'), name='newsletter_test_letter'),
url(r'^activation/send/', TemplateView.as_view(template_name='client/newsletters/activation_send.html'), url(r'^activation/send/', TemplateView.as_view(template_name='client/newsletters/activation_send.html'),
name='subscription_activation_send'), name='subscription_activation_send'),
url(r'^activation/complete/', TemplateView.as_view(template_name='client/newsletters/activation_complete.html'), url(r'^activation/complete/', TemplateView.as_view(template_name='client/newsletters/activation_complete.html'),

@ -3,7 +3,7 @@ import json
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
from django.views.generic import TemplateView, FormView from django.views.generic import TemplateView, FormView
from django.http import HttpResponseRedirect, HttpResponse from django.http import HttpResponse
from django.shortcuts import redirect from django.shortcuts import redirect
from emencia.django.newsletter.forms import ContactForm from emencia.django.newsletter.forms import ContactForm
@ -13,82 +13,97 @@ from emencia.django.newsletter.forms import (
) )
from accounts.models import User from accounts.models import User
from accounts.views import GetUserMixin from accounts.views import GetUserMixin
from functions.custom_views import ContextMixin from functions.http import JsonResponse
from city.models import City from city.models import City
class SubscribeView(GetUserMixin, ContextMixin, FormView): class SubscribeView(GetUserMixin, FormView):
form_class = ContactForm """
Представление для подписки не/авторизованных пользователей
"""
template_name = 'client/newsletters/mailing_settings.html' template_name = 'client/newsletters/mailing_settings.html'
success_url = reverse_lazy('subscription_activation_send') form_class = MailingSettingsForm
def get_form(self, form_class): def get_object(self):
if self.request.POST: return self.get_user()
email = self.request.POST.get('email')
if email: def get(self, request, *args, **kwargs):
try: self.object = self.get_object()
contact = Contact.objects.get(email=email) return super(SubscribeView, self).get(request, *args, **kwargs)
return form_class(instance=contact,
**self.get_form_kwargs()) def post(self, request, *args, **kwargs):
except Contact.DoesNotExist: self.object = self.get_object()
pass return super(SubscribeView, self).post(request, *args, **kwargs)
return form_class(**self.get_form_kwargs())
else:
return form_class(**self.get_form_kwargs())
def form_valid(self, form): def form_valid(self, form):
contact = form.save() if self.request.POST.get('save'):
contact.send_activation() contact = form.save()
return HttpResponseRedirect(self.success_url) if not self.request.user.is_authenticated():
contact.send_activation()
if self.request.is_ajax():
data = {'success': True}
if self.request.POST.get('save'):
data['redirect_url'] = str(self.get_success_url())
return JsonResponse(data)
return redirect(self.get_success_url())
def form_invalid(self, form):
if self.request.is_ajax():
data = {
'form_errors': form.errors,
}
return JsonResponse(data, status=400)
return self.render_to_response(self.get_context_data(form=form))
def get_initial(self): def get_initial(self):
data = super(SubscribeView, self).get_initial() data = super(SubscribeView, self).get_initial()
if self.request.user.is_authenticated(): if self.request.GET.get('email'):
email = getattr(self.request.user, 'email') data['email'] = self.request.GET['email']
data['email'] = email if self.request.GET.get('first_name'):
data['first_name'] = getattr(self.request.user, 'first_name') data['first_name'] = self.request.GET['first_name']
if self.request.GET:
if self.request.GET.get('email'):
data['email'] = self.request.GET['email']
if self.request.GET.get('first_name'):
data['first_name'] = self.request.GET['first_name']
return data return data
def get_form_kwargs(self):
kwargs = super(SubscribeView, self).get_form_kwargs()
if self.request.user.is_authenticated():
kwargs.update({'instance': self.object})
return kwargs
def get_success_url(self):
if not self.request.user.is_authenticated():
return reverse_lazy('subscription_activation_send')
return reverse_lazy('newsletter_subscription')
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
ctx = super(SubscribeView, self).get_context_data(**kwargs) ctx = super(SubscribeView, self).get_context_data(**kwargs)
ctx['object'] = self.get_mailsettings_object() ctx['object'] = self.object
ctx['mailsettings_form'] = MailingSettingsForm( ctx['r_cities'] = self.get_russian_cities()
instance=self.get_user() ctx['checked_th'] = self.get_checked_th()
)
if self.object is not None:
if self.request.GET.get('unsibscribe') and self.object.subscriber:
self.object.unsubscribe()
ctx['unsubscribe_success'] = True
elif not self.object.subscriber:
ctx['unsubscribed'] = True
return ctx return ctx
def get_mailsettings_object(self): def get_russian_cities(self):
"""
:return: города России
"""
return City.used.russia()
def get_checked_th(self):
""" """
передаём контекст в шаблон по городам, странам, а так же выбранным :return: выбранные пользователем темы
:return: instance of mail settings
""" """
self.extra_ctx.update({ if self.object is not None:
'r_cities': City.used.russia(), return self.object.themes.values_list('pk', flat=True)
}) return []
instance = self.get_user()
if instance is not None:
self.extra_ctx.update({
'checked_f_countries': list(
instance.f_countries.values_list('pk', flat=True)),
'checked_r_cities': list(
instance.r_cities.values_list('pk', flat=True)),
'checked_tg': list(instance.tags.values_list('pk', flat=True)),
'checked_th': list(
instance.themes.values_list('pk', flat=True)),
'contact': instance,
})
if self.request.GET.get('unsibscribe') and instance.subscriber:
instance.unsubscribe()
self.extra_ctx.update({'unsubscribe_success': True})
elif not instance.subscriber:
self.extra_ctx.update({'unsubscribed': True})
return instance
class ActivationView(TemplateView): class ActivationView(TemplateView):

@ -278,7 +278,7 @@ class ExpositionView(AdminView):
'expohit': obj.expohit, 'discount': obj.discount, 'expohit': obj.expohit, 'discount': obj.discount,
'canceled': obj.canceled, 'moved': obj.moved, 'logo': obj.logo, 'canceled': obj.canceled, 'moved': obj.moved, 'logo': obj.logo,
'visitors': obj.visitors, 'members': obj.members, 'visitors': obj.visitors, 'members': obj.members,
'audience':[item for item, bool in obj.audience.all() if bool], 'audience': [item for item in obj.audience.all()],
'quality_label': [item for item, bool in obj.quality_label if bool], 'quality_label': [item for item, bool in obj.quality_label if bool],
'place_alt': obj.place_alt} 'place_alt': obj.place_alt}

@ -49,7 +49,7 @@ class ExpositionCreateForm(forms.Form):
#company = forms.MultipleChoiceField(label=u'Компании', required=False, #company = forms.MultipleChoiceField(label=u'Компании', required=False,
# choices=[(item.id, item.name) for item in Company.objects.language().all()] ) # choices=[(item.id, item.name) for item in Company.objects.language().all()] )
country = forms.ChoiceField(label=_(u'Страна'), choices=[(c.id, c.name) for c in Country.objects.language().all()]) country = forms.ChoiceField(label=_(u'Страна'), choices=list(set([(c.id, c.name) for c in Country.objects.language().all()])))
theme = forms.MultipleChoiceField( theme = forms.MultipleChoiceField(
label=_(u'Тематики'), label=_(u'Тематики'),
choices=[(item.id, item.name) for item in Theme.objects.language().filter(types=Theme.types.exposition)]) choices=[(item.id, item.name) for item in Theme.objects.language().filter(types=Theme.types.exposition)])

@ -4,12 +4,15 @@ from django.views.decorators.csrf import csrf_exempt
from django.db.models.loading import get_model from django.db.models.loading import get_model
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.http import HttpResponse from django.http import HttpResponse
from django.views.generic import UpdateView from django.views.generic import FormView
from django.shortcuts import get_object_or_404
from django.conf import settings
from .models import FileModel from .models import FileModel
from .forms import FileForm, FileUpdateForm from .forms import FileForm, FileUpdateForm
import json import json
import magic
@csrf_exempt @csrf_exempt
@ -27,8 +30,15 @@ def ajax_post_file(request, obj_id):
if request.is_ajax() and request.method == 'POST': if request.is_ajax() and request.method == 'POST':
file_form = FileForm(request.POST, request.FILES) file_form = FileForm(request.POST, request.FILES)
if file_form.is_valid(): if file_form.is_valid():
file_form.save(request.FILES, obj) f = file_form.save(request.FILES, obj)
mime = magic.Magic(mime=True)
data['success'] = True data['success'] = True
data['name'] = f.file_name or f.file_path.name
data['size'] = f.file_path.size
data['file'] = f.file_path.url
data['type'] = mime.from_file(f.file_path.path)
data['remove_url'] = reverse('ajax_delete_file', args=[f.pk])
data['detail_link'] = reverse('file_update', args=[f.pk])
else: else:
data['errors'] = file_form.errors data['errors'] = file_form.errors
@ -39,11 +49,12 @@ def ajax_post_file(request, obj_id):
) )
files_data = [] files_data = []
for f in files: for f in files:
mime = magic.Magic(mime=True)
files_data.append({ files_data.append({
'name': f.file_name or f.file_path.name, 'name': f.file_name or f.file_path.name,
'size': f.file_path.size, 'size': f.file_path.size,
'file': f.file_path.url, 'file': f.file_path.url,
'type': 'file', 'type': mime.from_file(f.file_path.path),
'remove_url': reverse('ajax_delete_file', args=[f.pk]), 'remove_url': reverse('ajax_delete_file', args=[f.pk]),
'detail_link': reverse('file_update', args=[f.pk]) 'detail_link': reverse('file_update', args=[f.pk])
}) })
@ -66,10 +77,36 @@ def ajax_delete_file(request, id):
return HttpResponse(json.dumps(data), content_type='application/json') return HttpResponse(json.dumps(data), content_type='application/json')
class FileUpdateView(UpdateView): class FileUpdateView(FormView):
""" """
Представление обновления файла Представление обновления файла
""" """
template_name = 'c_admin/file/file_update.html' template_name = 'c_admin/file/file_update.html'
form_class = FileUpdateForm form_class = FileUpdateForm
model = FileModel
def get_object(self):
pk = self.kwargs.get('pk')
return get_object_or_404(FileModel, pk=pk)
def get_initial(self):
data = super(FileUpdateView, self).get_initial()
obj = self.get_object()
data['file_path'] = obj.file_path
data['purpose'] = obj.purpose
for lid, (code, name) in enumerate(settings.LANGUAGES):
data['file_name_%s' % code] = obj.file_name.translate(code)
data['description_%s' % code] = obj.description.translate(code)
return data
def form_valid(self, form):
form.save(self.request, self.kwargs.get('pk'))
return super(FileUpdateView, self).form_valid(form)
def get_success_url(self):
return reverse('file_update', args=[self.get_object().pk])
def get_context_data(self, **kwargs):
ctx = super(FileUpdateView, self).get_context_data(**kwargs)
ctx['object'] = self.get_object()
ctx['languages'] = settings.LANGUAGES
return ctx

@ -84,13 +84,46 @@ class FileForm(forms.Form):
return file_obj return file_obj
class FileUpdateForm(forms.ModelForm): class FileUpdateForm(forms.Form):
""" """
Форма обновления файла в админ панели Форма обновления файла в админ панели
""" """
class Meta: file_path = forms.FileField(label=_(u'Выберите файл'))
model = FileModel purpose = forms.ChoiceField(label=_(u'Назаначение'), choices=PURPOSES)
fields = ('file_path',)
def __init__(self, *args, **kwargs):
"""
Создаём динамические поля переводов
"""
super(FileUpdateForm, self).__init__(*args, **kwargs)
for lid, (code, name) in enumerate(settings.LANGUAGES):
self.fields['file_name_%s' % code] = forms.CharField(
label=_(u'Имя файла'),
required=False,
widget=forms.TextInput(attrs={'placeholder': 'Имя'})
)
self.fields['description_%s' % code] = forms.CharField(
label=_(u'Описание'),
required=False,
widget=CKEditorWidget()
)
def save(self, request, id=None):
data = self.cleaned_data
if id is None:
f = FileModel()
else:
f = FileModel.objects.get(id=id)
f.file_path = data['file_path']
f.purpose = data['purpose']
f.save()
# fill translated fields and save object
fill_trans_fields_all(FileModel, f, data, id=id)
return f
class FileModelForm(forms.Form): class FileModelForm(forms.Form):

@ -22,7 +22,7 @@ PURPOSES = (
('scheme teritory', _(u'Схема територии')), ('scheme teritory', _(u'Схема територии')),
('diplom', _(u'Дипломы')), ('diplom', _(u'Дипломы')),
('preview', _(u'Превью')), ('preview', _(u'Превью')),
('preview2', _(u'Превью')), ('preview2', _(u'Превью 2')),
) )

@ -284,7 +284,7 @@ event_sett = {
u'Основные темы': {u'field': u'main_themes', u'func': unicode}, u'Основные темы': {u'field': u'main_themes', u'func': unicode},
u'Условия и скидка': {u'field': u'discount_description', u'func': unicode}, u'Условия и скидка': {u'field': u'discount_description', u'func': unicode},
u'Периодичность': {u'field': u'periodic', u'func': to_periodic},### u'Периодичность': {u'field': u'periodic', u'func': to_periodic},###
u'Аудитория': {u'field': u'audience', u'func': to_audience}, u'Аудитория': {u'field': u'audience', u'func': to_audience, u'method': True},
u'Официальный веб-сайт': {u'field': u'web_page', u'func': to_url}, u'Официальный веб-сайт': {u'field': u'web_page', u'func': to_url},
u'Линк на регистрацию': {u'field': u'link', u'func': to_url}, u'Линк на регистрацию': {u'field': u'link', u'func': to_url},
u'Экспонируемые продукты': {u'field': u'products', u'func': unicode}, u'Экспонируемые продукты': {u'field': u'products', u'func': unicode},

@ -420,7 +420,6 @@ class ImportEventForm(ImportForm):
if setting is None: if setting is None:
continue continue
if setting.get('method'): if setting.get('method'):
# this cell contains data that must be written after creating object # this cell contains data that must be written after creating object
if cell != "": if cell != "":
@ -549,40 +548,39 @@ class ImportEventForm(ImportForm):
list_dicts.append(d) list_dicts.append(d)
"""
# go through row cells
# field name current cell
field_name = field_names[col_number]
if field_name =='theme':
# need save object before saving manytomany field
#object.save()
setting = import_settings.get(field_name)
d[setting] = cell
""" if setting is not None:
# go through row cells # if setting exist for this field
# field name current cell func = setting.get('func')
field_name = field_names[col_number] if func is not None:
if field_name =='theme': extra_value = setting.get('extra_values')
# need save object before saving manytomany field if extra_value is not None:
#object.save() # if setting has extra value then
setting = import_settings.get(field_name) # it is some field like city, theme, tag
d[setting] = cell # that has relation and can be created
if setting is not None: # in function we add language(need for relation fields)
# if setting exist for this field # and extra value from object (like for city need country)
func = setting.get('func') if cell:
if func is not None: value = func(cell, lang, getattr(object, extra_value))
extra_value = setting.get('extra_values') else:
if extra_value is not None: value = None
# if setting has extra value then else:
# it is some field like city, theme, tag value = func(cell)
# that has relation and can be created if value:
setattr(object, field_name, value)
# in function we add language(need for relation fields) """
# and extra value from object (like for city need country)
if cell:
value = func(cell, lang, getattr(object, extra_value))
else:
value = None
else:
value = func(cell)
if value:
setattr(object, field_name, value)
"""
#object.save() #object.save()

@ -6,9 +6,8 @@ from PIL import Image
from django.conf import settings from django.conf import settings
from django.utils import translation from django.utils import translation
from hvad.utils import get_translation_aware_manager from hvad.utils import get_translation_aware_manager
from bitfield import BitHandler
from place_exposition.models import PlaceExposition from place_exposition.models import PlaceExposition
from exposition.models import Exposition from events.models import TargetAudience
from country.models import Country from country.models import Country
from city.models import City from city.models import City
from theme.models import Theme, Tag from theme.models import Theme, Tag
@ -134,32 +133,29 @@ def to_periodic(value):
return periodic.get(value, 0) return periodic.get(value, 0)
def to_audience(value, model=Exposition): def to_audience(obj, value):
if value: # new_list = []
translation.activate('ru') # if value:
l = value.split(', ') # translation.activate('ru')
if l: # l = value.split(', ')
new_list = [] # target_audience = TargetAudience.objects.all()
for value in l: # print l
for item1, item2 in BIT_AUDIENCE: # for value in l:
if value == item2: # for ta in target_audience:
new_list.append(item1) # if value == ta.title:
if new_list: # new_list.append(ta.pk)
return reduce(lambda x,y: x|y, (getattr(model.audience, item) for item in new_list)) # return new_list
return 0 translation.activate('ru')
target_audience = TargetAudience.objects.filter(title__in=value.split(', ')).values_list('pk', flat=True)
obj.audience.clear()
obj.audience.add(*TargetAudience.objects.filter(id__in=target_audience))
return None
def get_audience(value): def get_audience(value):
if isinstance(value, BitHandler): new_list = [x.title for x in value.all()]
l = [k for k, v in value.iteritems() if v] return ', '.join(new_list)
if l:
new_list = []
for value in l:
for item1, item2 in BIT_AUDIENCE:
if value == item1:
new_list.append(unicode(item2))
return ', '.join(new_list)
return ''
import types import types
def save_logo(obj, path): def save_logo(obj, path):

@ -30,7 +30,7 @@ class ExpositionForm(forms.Form):
type = forms.ChoiceField(required=False, choices=types) type = forms.ChoiceField(required=False, choices=types)
logo = forms.ImageField(label=_(u'Logo'), required=False, max_length=500) logo = forms.ImageField(label=_(u'Logo'), required=False, max_length=500)
country = forms.ChoiceField(label=_(u'Страна'), choices=[(c.id, c.name) for c in Country.objects.language().all()]) country = forms.ChoiceField(label=_(u'Страна'), choices=list(set([(c.id, c.name) for c in Country.objects.language().all()])))
# creates select input with empty choices cause it will be filled with ajax # creates select input with empty choices cause it will be filled with ajax
city = forms.CharField(label=_(u'Город'), widget=forms.HiddenInput()) city = forms.CharField(label=_(u'Город'), widget=forms.HiddenInput())

@ -26,7 +26,7 @@ def ajax_city(request):
returns html <option> tags filled with cities filtered by country value from request returns html <option> tags filled with cities filtered by country value from request
""" """
objects = City.objects.language().filter(country=request.GET['id']).order_by('name') objects = City.objects.language().filter(country=request.GET['id']).order_by('name')
return render_to_response('select.html', {'objects': objects}) return render_to_response('c_admin/select.html', {'objects': objects})
def ajax_tag(request): def ajax_tag(request):

@ -416,7 +416,9 @@ CRONJOBS = [
('40 6 * * * ', 'django.core.management.call_command', ['newsletter_contacts_remove_notactivated']), ('40 6 * * * ', 'django.core.management.call_command', ['newsletter_contacts_remove_notactivated']),
('30 2 * * *', 'django.core.management.call_command', ['newsletter_create_dailymail']), ('30 2 * * *', 'django.core.management.call_command', ['newsletter_create_dailymail']),
('35 * * * *', 'django.core.management.call_command', ['send_newsletter']), # FIXME: команда временно переделана на отправку 1 письма.
# В свою очередь запуск по крону будет происходить допустим каждые 2 секунды
# ('35 * * * *', 'django.core.management.call_command', ['send_newsletter']),
('12 4 * * *', 'django.core.management.call_command', ['stats_daily']), ('12 4 * * *', 'django.core.management.call_command', ['stats_daily']),
('5 10 * * *', 'django.core.management.call_command', ['update_events_filter_fields']), ('5 10 * * *', 'django.core.management.call_command', ['update_events_filter_fields']),
@ -434,28 +436,6 @@ HAYSTACK_CONNECTIONS = {
}, },
} }
# TODO automate crons
"""
# update search indexes
0 * * * * /usr/bin/python /var/www/proj/manage.py update_index conference --remove --age=6
0 * * * * /usr/bin/python /var/www/proj/manage.py update_index exposition --remove --age=6
0 1,13 * * * /usr/bin/python /var/www/proj/manage.py update_index place_exposition --remove --age=24
0 3 * * * /usr/bin/python /var/www/proj/manage.py update_index company --remove --age=48
0 4 * * * /usr/bin/python /var/www/proj/manage.py update_index theme --remove --age=48
0 5 * * * /usr/bin/python /var/www/proj/manage.py update_index tag --remove --age=48
0 6 * * * /usr/bin/python /var/www/proj/manage.py update_index country --remove --age=48
0 7 * * * /usr/bin/python /var/www/proj/manage.py update_index city --remove --age=48
# update banner logs
10 * * * * /usr/bin/python /var/www/proj/manage.py banner_log_update
20 2,14 * * * /usr/bin/python /var/www/proj/manage.py banner_log_check_previous_day
# update hotels prices
20 1 * * 6 /usr/bin/python /var/www/proj/manage.py update_hotels_price
# newsletter
20 * * * * /usr/bin/python /var/www/proj/manage.py send_newsletter
40 6 * * * /usr/bin/python /var/www/proj/manage.py newsletter_contacts_remove_notactivated
"""
THUMBNAIL_ENGINE = "proj.sorlengine.SorlEngine" THUMBNAIL_ENGINE = "proj.sorlengine.SorlEngine"
THUMBNAIL_FORMAT = "PNG" THUMBNAIL_FORMAT = "PNG"

@ -44,6 +44,7 @@ pymorphy2==0.8
pymorphy2-dicts==2.4.393442.3710985 pymorphy2-dicts==2.4.393442.3710985
pysolr==3.2.0 pysolr==3.2.0
python-dateutil==2.2 python-dateutil==2.2
python-magic==0.4.12
python-memcached==1.48 python-memcached==1.48
python-openid==2.2.5 python-openid==2.2.5
python-social-auth==0.1.23 python-social-auth==0.1.23

@ -224,18 +224,17 @@ $(document).ready(function(){
$('.off').click(function(){ $('.off').click(function(){
var url = $(this).attr('href') var url = $(this).attr('href')
var $this = $(this) var $this = $(this)
$.get( $.get(url,function(data){
url, function(data){ if (data == 'off'){
if (data == 'off'){ $this.hide();
$this.hide(); $this.siblings('.on').show();
$this.siblings('.on').show(); }
} });
}
)
return false; return false;
}); });
// end on-of events // end on-of events
if( $("#id_city" ).length ) { if( $("#id_city").length ) {
$('#id_city').select2({ $('#id_city').select2({
placeholder: "Город", placeholder: "Город",
width: 'element', width: 'element',
@ -245,7 +244,7 @@ $(document).ready(function(){
dataType: "json", dataType: "json",
quietMillis: 200, quietMillis: 200,
data: function(term, page, country){ data: function(term, page){
var country = $('#id_country').val(); var country = $('#id_country').val();
return {term: term, return {term: term,
page: page, page: page,
@ -253,21 +252,23 @@ $(document).ready(function(){
}, },
results: function (data) { results: function (data) {
console.log('results');
if (typeof(data) == 'string'){ if (typeof(data) == 'string'){
data = JSON.parse(data); data = JSON.parse(data);
} }
console.log(data);
var results = []; var results = [];
$.each(data, function(index, item){ $.each(data, function(index, item){
results.push({ results.push({
id: item.id, id: item.id,
text: item.label text: item.label
}); });
}); });
return {results: results}; return {results: results};
} }
}, },
initSelection : function(element, callback) { initSelection : function(element, callback) {
var id= $(element).val(); var id = $(element).val();
var text = $(element).attr('data-init-text'); var text = $(element).attr('data-init-text');
callback({id: id, text:text}); callback({id: id, text:text});
} }
@ -325,13 +326,12 @@ $(document).ready(function(){
} }
if( $("#id_tag" ).length && $("#id_tag").is('select')) { try{
$('#id_tag').select2({ $('#id_tag').select2({
placeholder: "Теги", placeholder: "Теги",
width: '550px', width: '550px',
multiple: true, multiple: true,
ajax: { ajax: {
url: "/admin/theme/tag/search/", url: "/admin/theme/tag/search/",
dataType: "json", dataType: "json",
quietMillis: 200, quietMillis: 200,
@ -339,9 +339,11 @@ $(document).ready(function(){
data: function(term, page, theme){ data: function(term, page, theme){
var theme = $('#id_theme').serialize(); var theme = $('#id_theme').serialize();
return {term: term, return {
page: page, term: term,
theme: theme}; page: page,
theme: theme
};
}, },
results: function (data) { results: function (data) {
@ -365,10 +367,12 @@ $(document).ready(function(){
}); });
}); });
callback(data); callback(data);
} }
}); });
} catch (e) {
console.log('===== Error =====');
console.warn(e);
console.log('=================')
} }
@ -377,52 +381,55 @@ $(document).ready(function(){
*/ */
// theme change // theme change
$('#id_theme').change(function(){ $('#id_theme').change(function(){
$.get( $.get("/admin/ajax_tag/", {'id': $(this).serialize()}, function(data){
"/admin/ajax_tag/", {'id': $(this).serialize()}, function(data){ var optionValues = [];
var optionValues = []; var getValues = [];
var getValues = []; var selectedValues = [];
var selectedValues = []
//push values sended from server in array //push values sended from server in array
$.each(data, function(i, elem){ $.each(data, function(i, elem){
getValues.push(elem[0].toString()) getValues.push(elem[0].toString())
}); });
//delete options if they aren't in getvalues
//otherwise push it in array //delete options if they aren't in getvalues
//also push in array already selected values //otherwise push it in array
$('#id_tag option').each(function() { //also push in array already selected values
var check = $.inArray($(this), getValues); $('#id_tag option').each(function() {
if ($(this).is(':selected') ){ var check = $.inArray($(this), getValues);
selectedValues.push($(this).val()) if ($(this).is(':selected') ){
} selectedValues.push($(this).val())
if (check == -1){ }
$(this).remove() if (check == -1){
} $(this).remove()
else{ }
optionValues.push($(this).val()); else{
} optionValues.push($(this).val());
}); }
//generate new options });
//old options unchanged
var html = '' //generate new options
$.each(data, function(i, elem){ //old options unchanged
var check = $.inArray(elem[0].toString(), optionValues); var html = ''
$.each(data, function(i, elem){
if (check == -1){ var check = $.inArray(elem[0].toString(), optionValues);
html += '<option value="';
html += elem[0]; if (check == -1){
html += '">'; html += '<option value="';
html += elem[1]; html += elem[0];
html += '</option>'; html += '">';
} html += elem[1];
}); html += '</option>';
$('#id_tag').append(html); }
//select previous selected values });
$('#id_tag option').each(function() {
var check = $.inArray($(this).val(), selectedValues) $('#id_tag').append(html);
if (check != -1){ //select previous selected values
$(this).attr('selected', 'selected'); $('#id_tag option').each(function() {
} var check = $.inArray($(this).val(), selectedValues)
}); if (check != -1){
$(this).attr('selected', 'selected');
}
});
});//end get });//end get
});//end change });//end change
@ -499,7 +506,11 @@ $(document).ready(function(){
allowClear: true allowClear: true
}); });
} catch (e){} } catch (e){
console.log('===== Error =====');
console.warn(e);
console.log('=================');
}
} }

@ -1,52 +1,56 @@
// replace // replace
$(document).ready(function(){ $(document).ready(function(){
$('#id_theme').change(function(){ $('#id_theme').change(function(){
$.get( $.get("/admin/ajax_tag/", {'id': $(this).serialize()}, function(data){
"/admin/ajax_tag/", {'id': $(this).serialize()}, function(data){ var optionValues = [];
var optionValues = []; var getValues = [];
var getValues = []; var selectedValues = [];
var selectedValues = []
//push values sended from server in array
$.each(data, function(i, elem){
getValues.push(elem[0].toString())
});
//delete options if they aren't in getvalues
//otherwise push it in array
//also push in array already selected values
$('#id_tag option').each(function() {
var check = $.inArray($(this), getValues);
if ($(this).is(':selected') ){
selectedValues.push($(this).val())
}
if (check == -1){
$(this).remove()
}
else{
optionValues.push($(this).val());
}
});
//generate new options
//old options unchanged
var html = ''
$.each(data, function(i, elem){
var check = $.inArray(elem[0].toString(), optionValues);
if (check == -1){ //push values sended from server in array
html += '<option value="'; $.each(data, function(i, elem){
html += elem[0]; getValues.push(elem[0].toString())
html += '">'; });
html += elem[1];
html += '</option>'; //delete options if they aren't in getvalues
} //otherwise push it in array
}); //also push in array already selected values
$('#id_tag').append(html); $('#id_tag option').each(function() {
//select previous selected values var check = $.inArray($(this), getValues);
$('#id_tag option').each(function() { if ($(this).is(':selected') ){
var check = $.inArray($(this).val(), selectedValues) selectedValues.push($(this).val())
if (check != -1){ }
$(this).attr('selected', 'selected'); if (check == -1){
} $(this).remove()
}); }
});//end get else{
});//end change optionValues.push($(this).val());
});//end ready }
});
//generate new options
//old options unchanged
var html = '';
$.each(data, function(i, elem){
var check = $.inArray(elem[0].toString(), optionValues);
if (check == -1){
html += '<option value="';
html += elem[0];
html += '">';
html += elem[1];
html += '</option>';
}
});
$('#id_tag').append(html);
//select previous selected values
$('#id_tag option').each(function() {
var check = $.inArray($(this).val(), selectedValues)
if (check != -1){
$(this).attr('selected', 'selected');
}
});
});//end get
});//end change
});//end ready

@ -842,35 +842,84 @@ a.themes_trigger{
} }
.pr-form .pr-row{ .pr-form .pr-row{
overflow:hidden; /*overflow:hidden;*/
margin:0 0 14px; margin:0 0 14px;
} }
.pr-form .pr-row:after{
content: '';
display: block;
clear: both;
}
.pr-input{ .pr-input{
float:left; display: inline-block;
vertical-align: bottom;
margin:0 0 0 13px;
}
.errorlist{
list-style: none;
}
.text_error{
display: block;
text-align: center;
font-weight: 300;
font-size: 14px;
color: #bd2626;
padding-bottom: 3px;
}
.pr-input input.field_error{
box-shadow: 0 0 0 2px #f00;
}
.pr-input:first-child{
margin:0;
}
.pr-input.pr-name input{
background:#fff url(../images/pr-icon02.png) no-repeat 210px 50%;
}
.pr-input.pr-email input{
background:#fff url(../images/pr-icon03.png) no-repeat 210px 50%;
}
.pr-form input {
border:none;
color:#000;
font:17px/21px 'pf_dindisplay_promedium', Arial, Helvetica, sans-serif;
height:46px; height:46px;
width:186px; width:247px;
padding:0 44px 0 18px; padding:0 44px 0 18px;
margin:0 0 0 13px;
background:#fff; background:#fff;
border-radius:4px; border-radius:4px;
position:relative; position:relative;
} }
.pr-input:first-child{ .pr-form input:focus::-webkit-input-placeholder {
margin:0; color:transparent;
}
.pr-form input:focus:-moz-placeholder {
color:transparent;
}
.pr-form input:focus:-ms-input-placeholder {
color:transparent;
} }
.pr-input:after{ .pr-form input:focus::-moz-placeholder {
content:''; color:transparent;
position:absolute;
top:13px;
right:14px;
width:20px;
height:20px;
} }
.pr-input.pr-name:after{ .pr-form input::-webkit-input-placeholder { /* WebKit browsers */
background:url(../images/pr-icon02.png) no-repeat 50% 50%; color:#808080;
opacity:1;
} }
.pr-input.pr-email:after{ .pr-form input:-moz-placeholder { /* Mozilla Firefox 4 to 18 */
background:url(../images/pr-icon03.png) no-repeat 50% 50%; color:#808080;
opacity:1;
}
.pr-form input::-moz-placeholder { /* Mozilla Firefox 19+ */
color:#808080;
opacity:1;
}
.pr-form input:-ms-input-placeholder { /* Internet Explorer 10+ */
color:#808080;
opacity:1;
} }
.pr-form button{ .pr-form button{
@ -891,3 +940,7 @@ a.themes_trigger{
-o-transition: all 100ms linear; -o-transition: all 100ms linear;
transition: all 100ms linear; transition: all 100ms linear;
} }
.error_messages .errorlist{
list-style: decimal inside;
}

@ -1,13 +1,52 @@
'use strict'; 'use strict';
function sendForm () { function sendForm (show_modal) {
var $form = $('#mailing_settings_form'); var show_modal = show_modal || false,
$form = $('#mailing_settings_form');
$form.find('.field_error').removeClass('field_error');
$form.find('.text_error').remove();
var form_data = $form.serializeArray();
if (show_modal) {
form_data.push({
name: 'save',
value: true
})
}
$.ajax({ $.ajax({
url: $form.attr('action'), url: $form.attr('action'),
type: $form.attr('method'), type: $form.attr('method'),
data: $form.serializeArray(), data: form_data,
success: function(response){ success: function(response){
console.log(response); console.log(response);
if (response.hasOwnProperty('redirect_url')){
window.location.pathname = response.redirect_url;
}
},
error: function (error) {
var form_errors = error.responseJSON.form_errors;
if (show_modal){
var $error_list = $('<ol></ol>', {class: 'errorlist'});
$.each(form_errors, function (field, err) {
$error_list.append('<li>' + err + '</li>');
});
$('#error_messages').html($error_list);
$.fancybox.open({
href: '#error_modal'
})
} else {
$.each(form_errors, function (field, err) {
var $field = $form.find('#id_' + field);
$field.addClass('field_error');
$field.parent('.pr-input').prepend('<span class="text_error">' + err + '</span>');
});
}
} }
}); });
} }
@ -123,7 +162,6 @@ function sendForm () {
}); });
} }
function isAllTagsChecked (theme_id) { function isAllTagsChecked (theme_id) {
return themes_data[theme_id].tags.every(function (obj) { return themes_data[theme_id].tags.every(function (obj) {
return obj.checked; return obj.checked;
@ -361,6 +399,13 @@ function sendForm () {
$themes_modal.on('click', '.modal-approve', function () { $themes_modal.on('click', '.modal-approve', function () {
var $selected = $selected_themes.find('li').removeClass('unsaved').clone(); var $selected = $selected_themes.find('li').removeClass('unsaved').clone();
if ($('#pr-promo').length){
if (!$('#id_moscow').is(':checked') && !$('#id_russia').is(':checked') && $selected_themes.children().length && !$('#selected_themes').children().length){
$('#id_moscow').prop('checked', true);
$('#id_russia').prop('checked', true);
}
}
$('#selected_themes').html($selected); $('#selected_themes').html($selected);
sendForm(); sendForm();
@ -371,6 +416,12 @@ function sendForm () {
$selected_themes.find('a').trigger('click'); $selected_themes.find('a').trigger('click');
}); });
$('#mailing_settings_form button').on('click', function (event) {
event.preventDefault();
var show_modal = true;
sendForm(show_modal);
});
})(); })();

@ -15,17 +15,17 @@
<link href="{% static 'js/datetimepicker/css/datetimepicker.css' %}" rel="stylesheet"/> <link href="{% static 'js/datetimepicker/css/datetimepicker.css' %}" rel="stylesheet"/>
<script src="{% static 'js/datetimepicker/js/bootstrap-datetimepicker.js' %}"></script> <script src="{% static 'js/datetimepicker/js/bootstrap-datetimepicker.js' %}"></script>
<script> <script>
$(document).ready(function(){ $(document).ready(function(){
$('#id_publish_date').datetimepicker({ $('#id_publish_date').datetimepicker({
todayHighlight: true, todayHighlight: true,
format : 'yyyy-mm-dd', format : 'yyyy-mm-dd',
minView:2 minView:2
}); });
}); });
</script>
</script>
<link rel="stylesheet" href="{% static 'jQuery-filer/css/jquery.filer.css' %}"> <link rel="stylesheet" href="{% static 'jQuery-filer/css/jquery.filer.css' %}">
<link rel="stylesheet" href="{% static 'jQuery-filer/css/jquery.filer-dragdropbox-theme.css' %}"> <link rel="stylesheet" href="{% static 'jQuery-filer/css/jquery.filer-dragdropbox-theme.css' %}">
<script src="{% static 'jQuery-filer/js/jquery.filer.js' %}"></script> <script src="{% static 'jQuery-filer/js/jquery.filer.js' %}"></script>
@ -43,6 +43,7 @@
<div class="box-header well"> <div class="box-header well">
<h2><i class="icon-pencil"></i> {% trans "Основная информация" %}</h2> <h2><i class="icon-pencil"></i> {% trans "Основная информация" %}</h2>
</div> </div>
<div class="box-content"> <div class="box-content">
{# main_title #} {# main_title #}
@ -50,35 +51,38 @@
<div class="control-group {% if form.publish_date.errors %}error{% endif %}"> <div class="control-group {% if form.publish_date.errors %}error{% endif %}">
<label class="control-label"><b>{{ form.publish_date.label }}:</b></label> <label class="control-label"><b>{{ form.publish_date.label }}:</b></label>
<div class="controls"> <div class="controls">
{{ form.publish_date }} {{ form.publish_date }}
<span class="help-inline">{{ form.publish_date.errors }}</span> <span class="help-inline">{{ form.publish_date.errors }}</span>
</div> </div>
</div> </div>
{% if not article %} {% if not article %}
<div class="control-group {% if form.slug.errors %}error{% endif %}"> <div class="control-group {% if form.slug.errors %}error{% endif %}">
<label class="control-label">{{ form.slug.label }}:</label> <label class="control-label">{{ form.slug.label }}:</label>
<div class="controls"> <div class="controls">
{{ form.slug }} {{ form.slug }}
<span class="help-inline">{{ form.slug.errors }}</span> <span class="help-inline">{{ form.slug.errors }}</span>
</div> </div>
</div> </div>
{% endif %} {% endif %}
{# theme #} {# theme #}
<div class="control-group {% if form.theme.errors %}error{% endif %}"> <div class="control-group {% if form.theme.errors %}error{% endif %}">
<label class="control-label"><b>{{ form.theme.label }}:</b></label> <label class="control-label"><b>{{ form.theme.label }}:</b></label>
<div class="controls"> <div class="controls">
{{ form.theme }} {{ form.theme }}
<span class="help-inline">{{ form.theme.errors }}</span> <span class="help-inline">{{ form.theme.errors }}</span>
</div> </div>
</div> </div>
{# tag #} {# tag #}
<div class="control-group {% if form.tag.errors %}error{% endif %}"> <div class="control-group {% if form.tag.errors %}error{% endif %}">
<label class="control-label">{{ form.tag.label }}:</label> <label class="control-label">{{ form.tag.label }}:</label>
<div class="controls"> <div class="controls">
{{ form.tag }} {{ form.tag }}
<span class="help-inline">{{ form.tag.errors }}</span> <span class="help-inline">{{ form.tag.errors }}</span>
</div> </div>
</div> </div>
{# exposition #} {# exposition #}
{% if form.exposition %} {% if form.exposition %}
@ -160,78 +164,78 @@
{% block bot_scripts %} {% block bot_scripts %}
<script> <script>
$(document).ready(function(){ $(document).ready(function(){
$('#id_exposition').select2({ $('#id_exposition').select2({
placeholder: "Выставка", placeholder: "Выставка",
multiple: false, multiple: false,
width: 'element', width: 'element',
ajax: { ajax: {
url: "/admin/exposition/search/", url: "/admin/exposition/search/",
width: '550px', width: '550px',
dataType: "json", dataType: "json",
quietMillis: 200, quietMillis: 200,
data: function(term, page, theme){ data: function(term, page, theme){
return {term: term, return {term: term,
page: page}; page: page};
}, },
results: function (data) { results: function (data) {
var results = []; var results = [];
$.each(data, function(index, item){ $.each(data, function(index, item){
results.push({ results.push({
id: item.id, id: item.id,
text: item.label text: item.label
}); });
}); });
return {results: results}; return {results: results};
} }
}, },
initSelection : function(element, callback) { initSelection : function(element, callback) {
var id= $(element).val(); var id= $(element).val();
var text = $(element).attr('data-init-text'); var text = $(element).attr('data-init-text');
callback({id: id, text:text}); callback({id: id, text:text});
} }
}); });
$('#id_conference').select2({ $('#id_conference').select2({
placeholder: "Конференция", placeholder: "Конференция",
multiple: false, multiple: false,
width: 'element', width: 'element',
ajax: { ajax: {
url: "/admin/conference/search/", url: "/admin/conference/search/",
width: '550px', width: '550px',
dataType: "json", dataType: "json",
quietMillis: 200, quietMillis: 200,
data: function(term, page, theme){ data: function(term, page, theme){
return {term: term, return {term: term,
page: page}; page: page};
}, },
results: function (data) { results: function (data) {
var results = []; var results = [];
$.each(data, function(index, item){ $.each(data, function(index, item){
results.push({ results.push({
id: item.id, id: item.id,
text: item.label text: item.label
}); });
}); });
return {results: results}; return {results: results};
} }
}, },
initSelection : function(element, callback) { initSelection : function(element, callback) {
var id= $(element).val(); var id= $(element).val();
var text = $(element).attr('data-init-text'); var text = $(element).attr('data-init-text');
callback({id: id, text:text}); callback({id: id, text:text});
} }
}); });
}); });
</script> </script>
{% endblock %} {% endblock %}

@ -1,7 +1,13 @@
{% extends 'c_admin/base.html' %} {% extends 'c_admin/base.html' %}
{% load static %}
{% block scripts %}
<script src="{% static 'ckeditor/ckeditor/ckeditor.js' %}"></script>
{% endblock %}
{% block body %} {% block body %}
<form action="." method="post" enctype="multipart/form-data" class="form-horizontal"> <form action="." method="post" enctype="multipart/form-data" class="form-horizontal">
{% csrf_token %}
<fieldset> <fieldset>
<legend><i class="icon-edit"></i>{% if object %} Изменить {% else %} Добавить {% endif %} файл</legend> <legend><i class="icon-edit"></i>{% if object %} Изменить {% else %} Добавить {% endif %} файл</legend>
@ -10,7 +16,33 @@
<h2><i class="icon-pencil"></i> Основная информация</h2> <h2><i class="icon-pencil"></i> Основная информация</h2>
</div> </div>
<div class="box-content"> <div class="box-content">
{{ form.as_p }} {# {{ form.as_p }}#}
{% with field='file_name' form=form languages=languages %}
{% include 'c_admin/forms/multilang.html' %}
{% endwith %}
<div class="control-group {% if form.file_path.errors %}error{% endif %}">
<label class="control-label">
<b>{{ form.file_path.label }}:</b>
</label>
<div class="controls">{{ form.file_path }}
<span class="help-inline">{{ form.file_path.errors }}</span>
</div>
</div>
<div class="control-group {% if form.purpose.errors %}error{% endif %}">
<label class="control-label">
<b>{{ form.purpose.label }}:</b>
</label>
<div class="controls">{{ form.purpose }}
<span class="help-inline">{{ form.purpose.errors }}</span>
</div>
</div>
{% with field='description' form=form languages=languages %}
{% include 'c_admin/forms/multilang.html' %}
{% endwith %}
</div> </div>

@ -152,8 +152,8 @@
<div class="controls"> <div class="controls">
<button id="submit" class="btn btn-primary">Фильтровать</button> <button id="submit" class="btn btn-primary">Фильтровать</button>
<a href="{% url 'export_contacts' %}" id="export" class="btn yellow">Экспорт<i class="icon-circle-arrow-down"></i></a> <a href="{% url 'export_contacts' %}" id="export" class="btn yellow">Экспорт<i class="icon-circle-arrow-down"></i></a>
<a href="{% url 'newsletters_mailinglist_create_filter' %}" id="mailinglist" class="btn btn-success" data-toggle="tooltip" data-placement="top" title="Создает новый список рассылки с отфильтрованими контактами"><i class="icon-plus"></i>Создать список рассылки из фильтра</i></a> <a href="{% url 'newsletters_mailinglist_create_filter' %}" id="mailinglist" class="btn btn-success" data-toggle="tooltip" data-placement="top" title="Создает новый список рассылки с отфильтрованими контактами"><i class="icon-plus"></i>Создать список рассылки из фильтра</a>
<a href="{% url 'newsletters_mailinglist_create' %}" class="btn btn-success" data-toggle="tooltip" data-placement="top" title="Создает новый список рассылки"><i class="icon-plus"></i>Создать список рассылки</i></a> <a href="{% url 'newsletters_mailinglist_create' %}" class="btn btn-success" data-toggle="tooltip" data-placement="top" title="Создает новый список рассылки"><i class="icon-plus"></i>Создать список рассылки</a>
</div> </div>
</div> </div>
</div> </div>

@ -65,6 +65,8 @@
<i class="icon-info-sign"></i>{% trans "Доступные параметры для прехедера" %}: <i class="icon-info-sign"></i>{% trans "Доступные параметры для прехедера" %}:
<p>{% trans "{name} - имя пользователя" %}</p> <p>{% trans "{name} - имя пользователя" %}</p>
<p>{% trans "{themes} - темы на которые пользователь подписан (первые 3 + кол-во оставшихся)" %}</p> <p>{% trans "{themes} - темы на которые пользователь подписан (первые 3 + кол-во оставшихся)" %}</p>
<i class="icon-info-sign"></i>{% trans "Доступные параметры для контента" %}:
<p>{% trans "{name} - имя пользователя" %}</p>
</div> </div>
<div class="box-content"> <div class="box-content">

@ -16,13 +16,13 @@
<script src="{% static 'ckeditor/ckeditor/ckeditor.js' %}"></script> <script src="{% static 'ckeditor/ckeditor/ckeditor.js' %}"></script>
{# google map не забыть скачать скрипты на локал #} {# google map не забыть скачать скрипты на локал #}
<link href='https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/themes/redmond/jquery-ui.css' rel="stylesheet"/> <link href='https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/themes/redmond/jquery-ui.css' rel="stylesheet"/>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'></script> {# <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'></script>#}
<script src='https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js'></script> <script src='https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js'></script>
<script src='https://maps.google.com/maps/api/js?sensor=false'></script> <script src='https://maps.google.com/maps/api/js?sensor=false'></script>
{# selects #} {# selects #}
<link href="{% static 'js/select/select2.css' %}" rel="stylesheet"/> {# <link href="{% static 'js/select/select2.css' %}" rel="stylesheet"/>#}
<script src="{% static 'js/select/select2.js' %}"></script> {# <script src="{% static 'js/select/select2.js' %}"></script>#}
<script src="{% static 'custom_js/formset_add.js' %}"></script> {# <script src="{% static 'custom_js/formset_add.js' %}"></script>#}
{# ajax #} {# ajax #}
<!-- <script src="{% static 'custom_js/file_post_ajax.js' %}"></script>--> <!-- <script src="{% static 'custom_js/file_post_ajax.js' %}"></script>-->

@ -10,7 +10,6 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/malihu-custom-scrollbar-plugin/3.1.5/jquery.mCustomScrollbar.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/malihu-custom-scrollbar-plugin/3.1.5/jquery.mCustomScrollbar.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css">
<link rel="stylesheet" href="{% static 'mailing_settings/css/main.css' %}"> <link rel="stylesheet" href="{% static 'mailing_settings/css/main.css' %}">
<link rel="stylesheet" href="{% static 'mailing_settings/css/form.css' %}">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js" defer></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js" defer></script>
</head> </head>
@ -20,16 +19,16 @@
<header class="page_header"> <header class="page_header">
<div class="container"> <div class="container">
<div class="logo_block"> <div class="logo_block">
<a href="/"><img src="{% static 'mailing_settings/images/logo.png' %}" alt="Expomap"></a> <a href="{% url 'index' %}"><img src="{% static 'mailing_settings/images/logo.png' %}" alt="Expomap"></a>
<a href="/" class="back_to_site">expomap.ru <span>&#8250;</span></a> <a href="{% url 'index' %}" class="back_to_site">expomap.ru <span>&#8250;</span></a>
</div> </div>
<h1>{% trans 'Настройте рассылку от Expomap' %}</h1> <h1>{% trans 'Настройте рассылку от Expomap' %}</h1>
<p>{% trans 'для' %} <span>{{ contact.email }}</span></p> <p>{% trans 'для' %} <span>{{ object.email }}</span></p>
</div> </div>
</header> </header>
{% else %} {% else %}
<header id="pr-header"> <header id="pr-header">
<div class="pr-center"> <div class="container">
<div class="pr-header-box"> <div class="pr-header-box">
<a class="pr-phone" href="tel:+7 (499) 999-12-07">+7 (499) 999-12-07</a> <a class="pr-phone" href="tel:+7 (499) 999-12-07">+7 (499) 999-12-07</a>
<ul class="pr-social"> <ul class="pr-social">
@ -41,13 +40,215 @@
<li><a href="https://twitter.com/expomap_ru"><img src="{% static 'mailing_settings/images/sm-icon-twit.png' %}" /></a></li> <li><a href="https://twitter.com/expomap_ru"><img src="{% static 'mailing_settings/images/sm-icon-twit.png' %}" /></a></li>
</ul> </ul>
</div> </div>
<strong class="pr-logo"><a href="/">Expomap</a></strong> <strong class="pr-logo"><a href="{% url 'index' %}">Expomap</a></strong>
<span class="pr-slogan">{% blocktrans %}П<span class="pr-search-icon"></span>исковик деловых событий{% endblocktrans %}</span> <span class="pr-slogan">{% blocktrans %}П<span class="pr-search-icon"></span>исковик деловых событий{% endblocktrans %}</span>
</div> </div>
</header> </header>
{% endif %} {% endif %}
<p>Страница в разработке</p> <form action="." method="post" id="mailing_settings_form">
{% csrf_token %}
{% if not user.is_authenticated %}
<section id="pr-promo">
<div class="container">
<h1>{% trans 'Анонсы выставок' %} <br />{% trans 'и конференций на ваш e-mail' %}</h1>
<h2>{% trans 'Хотите быть в курсе событий?' %}</h2>
<div class="pr-promo-text">
<p>{% trans 'Получайте анонсы выставок и конференций на email каждую среду. Вы можете выбрать несколько интересующих вас тематических направлений.' %} <a target="_blank" href="{% url 'newsletter_test_letter' %}">{% trans 'Пример письма' %}</a></p>
</div>
<div class="pr-form">
<fieldset>
<div class="pr-row">
<span class="pr-input pr-name {% if form.first_name.errors %}field_error{% endif %}">
{% if form.first_name.errors %}<span class="text_error">{{ form.first_name.errors }}</span>{% endif %}
{{ form.first_name }}
</span>
<span class="pr-input pr-email {% if form.email.errors %}field_error{% endif %}">
{% if form.email.errors %}<span class="text_error">{{ form.email.errors }}</span>{% endif %}
{{ form.email }}
</span>
</div>
<button>{% trans 'Подписаться' %}</button>
</fieldset>
</div>
</div>
</section>
{% endif %}
<div class="themes_block">
<div class="container">
<h2>{% trans 'Какие события включать в ваше письмо?' %}</h2>
<div class="columns">
<div class="column">
<h3>{% trans 'Ваши темы:' %}</h3>
<ul id="selected_themes" class="selected selected_themes">
{% for theme in object.themes.all %}
<li data-id="{{ theme.pk }}" data-type="th" class="theme_{{ theme.pk }}">
<input type="hidden" name="th" value="{{ theme.pk }}">
{{ theme }}
<a href="#">&times;</a>
</li>
{% endfor %}
{% for tag in object.tags.all %}
<li data-id="{{ tag.pk }}" data-type="tg" data-parent="{{ tag.theme.pk }}" class="tag_{{ tag.pk }}">
<input type="hidden" name="tg" value="{{ tag.pk }}">
{{ tag }}
<a href="#">&times;</a>
</li>
{% endfor %}
</ul>
<a href="#search-modal" class="modal_trigger themes_trigger">{% trans 'Уточнить темы' %}</a>
</div>
<div class="column">
<h3>{% trans 'Ваши гео-фильтры:' %}</h3>
<ul class="geo_filters">
<li>
<label>
{{ form.moscow }}
<span class="label moscow">
<i class="fa fa-map-marker"></i>
{{ form.moscow.label }}
</span>
<span class="geo_checkbox"></span>
</label>
</li>
<li>
<label>
{{ form.russia }}
<span class="label rf">
<i class="fa fa-map-marker"></i>
{{ form.russia.label }}
</span>
<span class="geo_checkbox"></span>
</label>
<a href="#cities-modal" class="modal_trigger">{% trans 'Выбрать города' %}</a>
<ul id="selected_cities" class="selected"></ul>
{{ form.r_cities }}
</li>
<li>
<label>
{{ form.foreign }}
<span class="label foreign">
<i class="fa fa-map-marker"></i>
{{ form.foreign.label }}
</span>
<span class="geo_checkbox"></span>
</label>
<a href="#countries_modal" class="modal_trigger">{% trans 'Выбрать страны' %}</a>
<ul id="selected_areas" class="selected"></ul>
<ul id="selected_countries" class="selected"></ul>
{{ form.area }}
{{ form.co }}
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="subjects_block">
<div class="container">
<h2>{% trans 'Включать ли новости / обзоры / статьи в письмо?' %}</h2>
<div class="columns">
<div class="column">
{{ form.content_news }}
{{ form.content_news.label_tag }}
<p>{% trans "Получайте новости выставок и конференций по выбранным тематикам" %}</p>
</div>
<div class="column">
{{ form.content_overview }}
{{ form.content_overview.label_tag }}
<p>{% trans "Практические материалы, интервью, кейсы, которые помогут эффективно участвовать в выставках" %}</p>
</div>
<div class="column">
{{ form.content_articles }}
{{ form.content_articles.label_tag }}
<p>{% trans "Блог о том, как создавать и продвигать крутые event`ы" %}</p>
</div>
</div>
</div>
</div>
<div class="period_block">
<div class="container">
<h2>{% trans 'Регулярность получения писем' %}</h2>
<div class="columns">
<div class="column periodic">
<ul>
{% for field in form.periodic %}
<li>
<label>
{{ field.tag }}
<span class="radio">
{{ field.choice_label }}
</span>
</label>
</li>
{% endfor %}
</ul>
</div>
<div class="column mailing_day">
{% for field in form.periodic_day %}
<label>
{{ field.tag }}
<span class="radio">
{{ field.choice_label }}
</span>
</label>
{% endfor %}
</div>
</div>
</div>
</div>
<div class="button_block">
<div class="container">
{% if not user.is_authenticated %}
<div class="tos">
<strong>{% trans 'Нажимая «Подписаться», вы соглашаетесь получать' %} <br /> {% trans 'материалы компании Expomap на свой электронный адрес' %} </strong>
<a href="{% url 'termsofuse' %}" style="color:#a2a2a2;">{% trans "Пользовательское соглашение" %}</a>
</div>
{% endif %}
<button type="submit">
{% if user.is_authenticated %}
{% trans "Сохранить" %}
{% else %}
{% trans 'Подписаться' %}
{% endif %}
</button>
{% if user.is_authenticated %}
<a href="?unsibscribe=1">{% trans 'Не хочу быть в курсе событий (отписаться от всего)' %}</a>
{% endif %}
</div>
</div>
</form>
<footer class="page_footer">&copy; Expomap {% now "Y" %}</footer>
<div class="modals">
<div id="search-modal">
{% include 'client/popups/new_themes.html' %}
</div>
<div id="cities-modal">
{% include 'client/popups/russia_cities.html' %}
</div>
<div id="countries_modal">
{% include 'client/popups/mailing_settings_countries.html' %}
</div>
{% if unsubscribe_success or unsubscribed %}
<div id="unsibscribed_modal">
{% include 'client/popups/unsubscribed.html' %}
</div>
{% endif %}
<div id="error_modal">
<div class="popup-window">
<header>
<div class="title">{% trans 'Ошибка' %}</div>
</header>
<div class="body error_messages" id="error_messages"></div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fancybox/2.1.4/jquery.fancybox.pack.min.js" defer></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/fancybox/2.1.4/jquery.fancybox.pack.min.js" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/malihu-custom-scrollbar-plugin/3.1.5/jquery.mCustomScrollbar.min.js" defer></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/malihu-custom-scrollbar-plugin/3.1.5/jquery.mCustomScrollbar.min.js" defer></script>

@ -184,13 +184,12 @@
<div class="rq-note"> <div class="rq-note">
{% if object %} {% if object %}
<p> <p>
{% trans 'Укажите в запросе исходную информацию о Ваших целях и задачах, и мы подберем' %} {{ object.name }} {% trans 'Укажите в запросе исходную информацию о ваших целях и задачах, и мы проанализируем, насколько' %} {{ object.name }}
{% trans 'которая будет им соответствовать. Далее мы свяжемся с организаторами, чтобы уточнить наличие свободных площадей и цены, и вместе с Вами начнем создавать концепцию Вашего участия." На "Укажите в запросе исходную информацию о Ваших целях и задачах, и мы проанализируем, насколько' %} {{ object.name }} {% trans 'им соответствует. Далее мы свяжемся с организаторами, чтобы уточнить наличие свободных площадей и цены, и вместе с вами начнем создавать концепцию вашего участия.' %}
{% trans 'им соответствует. Далее мы свяжемся с организаторами, чтобы уточнить наличие свободных площадей и цены, и вместе с Вами начнем создавать концепцию Вашего участия.' %}
</p> </p>
{% else %} {% else %}
<p> <p>
{% trans 'Укажите в запросе исходную информацию о Ваших целях и задачах, и мы подберем выставку которая будет им соответствовать. Далее мы свяжемся с организаторами, чтобы уточнить наличие свободных площадей и цены, и вместе с Вами начнем создавать концепцию Вашего участия.'%} {% trans 'Укажите в запросе исходную информацию о ваших целях и задачах, и мы проанализируем, насколько событие им соответствует. Далее мы свяжемся с организаторами, чтобы уточнить наличие свободных площадей и цены, и вместе с вами начнем создавать концепцию вашего участия.' %}
</p> </p>
{% endif %} {% endif %}
</div> </div>

Loading…
Cancel
Save