diff --git a/.gitignore b/.gitignore index 3fc5210e..1ded53a1 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ npm-debug.log + +node_modules \ No newline at end of file diff --git a/accounts/models.py b/accounts/models.py index 917c646c..ce4e4b47 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -205,6 +205,11 @@ class User(AbstractBaseUser, PermissionsMixin): return '/%d/'%self.id #return self.catalog+str(self.id)+'/' + def get_translator_url(self): + if self.url: + return '/translators/%s/'%self.url + return '/translators/%d/'%self.id + def get_expos(self): """ return information about expos and them related data by 1 query diff --git a/banners/models.py b/banners/models.py index b9779288..8cd34977 100644 --- a/banners/models.py +++ b/banners/models.py @@ -5,6 +5,8 @@ from django.db import models class Redirect(models.Model): redirect = models.URLField() count = models.PositiveIntegerField(default=0) + views = models.PositiveIntegerField(default=0) + def __unicode__(self): return self.redirect diff --git a/city/admin.py b/city/admin.py index adf383e3..b2642e36 100644 --- a/city/admin.py +++ b/city/admin.py @@ -49,14 +49,14 @@ def city_change(request, url): return HttpResponseRedirect('/admin/city/all') if request.POST: - form = CityForm(request.POST) + form = CityForm(request.POST, request.FILES) if form.is_valid(): form.save(city_id) return HttpResponseRedirect('/admin/city/all') else: #fill form with data from database data = {'population' : c.population, 'phone_code' : c.phone_code, - 'city_id' : city_id, 'inflect':c.inflect} + 'city_id' : city_id, 'inflect':c.inflect, 'logo': c.logo} if c.country: data['country'] = c.country.id diff --git a/city/forms.py b/city/forms.py index 98cc5ce5..8843c223 100644 --- a/city/forms.py +++ b/city/forms.py @@ -34,6 +34,7 @@ class CityForm(forms.Form): widget=forms.TextInput(attrs={'placeholder':'Код города'})) code_IATA = forms.ModelChoiceField(label='Код IATA', queryset=Iata.objects.all(), empty_label=None, required=False) inflect = forms.CharField(label='Inflect', required=False) + logo = forms.ImageField(label='Logo', required=False) #field for comparing tmp files key = forms.CharField(required=False, widget=forms.HiddenInput()) # @@ -91,6 +92,11 @@ class CityForm(forms.Form): city.population = data.get('population') city.inflect = data['inflect'] + if data.get('logo'): + city.logo = data['logo'] + else: + city.logo = '' + if data.get('code_IATA'): city.code_IATA = Iata.objects.get(id=data['code_IATA'].id)# .id cause select uses queryset @@ -161,4 +167,17 @@ class CityDeleteForm(forms.ModelForm): class CityFilterForm(AdminFilterForm): - model = City \ No newline at end of file + country = forms.ChoiceField(choices=[('', '')]+[(item.id, item.name) for item in Country.objects.all()], required=False, + label='Страна') + model = City + + def filter(self): + qs = super(CityFilterForm, self).filter() + + data = self.cleaned_data + country_id = data['country'] + + + if country_id: + qs = qs.filter(country__id=country_id) + return qs diff --git a/city/models.py b/city/models.py index 73d3cbf5..aa4f4ead 100644 --- a/city/models.py +++ b/city/models.py @@ -2,6 +2,7 @@ from datetime import date from django.db import models from django.db.models.signals import post_save, pre_save +from django.utils import translation from hvad.models import TranslatableModel, TranslatedFields, TranslationManager from bitfield import BitField from sorl.thumbnail import ImageField @@ -62,6 +63,7 @@ class City(TranslatableModel): # fields saves information about creating and changing model created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) + logo = models.ImageField(verbose_name='Logo', upload_to='city/logo/', blank=True, max_length=255) class Meta: ordering = ['translations__name'] @@ -115,6 +117,12 @@ class City(TranslatableModel): def get_sub_categories(self): return [] + def get_index_text(self): + translation.activate('ru') + translations = self.translations.all() + names = ' '.join([tr.name for tr in translations]) + return names + diff --git a/city/search_indexes.py b/city/search_indexes.py index c9c457d3..8d54a854 100644 --- a/city/search_indexes.py +++ b/city/search_indexes.py @@ -1,18 +1,36 @@ +# -*- coding: utf-8 -*- +from django.utils import translation from haystack import indexes from models import City +from functions.search_mixin import ExpoSearchMixin -""" -class CityIndex(indexes.SearchIndex, indexes.Indexable): + +class CountryIndex(indexes.SearchIndex, indexes.Indexable, ExpoSearchMixin): text = indexes.CharField(document=True, use_template=True) - translations = indexes.MultiValueField() - #name = indexes.CharField(model_attr='translations__name') + url = indexes.CharField() + content_auto = indexes.EdgeNgramField() + form_name = indexes.CharField() + # translated fields + name_en = indexes.CharField() + name_ru = indexes.CharField() + catalog_name_en = indexes.CharField() + catalog_name_ru = indexes.CharField() + + def prepare_form_name(self, obj): + return 'ci' + + def prepare_catalog_name_en(self, obj): + return u'Cities' - def prepare_translations(self, obj): - return [tr.name for tr in obj.translations.all()] + def prepare_catalog_name_ru(self, obj): + return u'Города' def get_model(self): return City def index_queryset(self, using=None): - return self.get_model().objects.filter() -""" + + return self.get_model().used.all() + + def get_updated_field(self): + return 'modified' \ No newline at end of file diff --git a/conference/admin.py b/conference/admin.py index d5d063b5..af2f95c5 100644 --- a/conference/admin.py +++ b/conference/admin.py @@ -239,7 +239,7 @@ class ConferenceView(AdminView): 'link':obj.link, 'conference_id':obj.id, 'expohit': obj.expohit, 'periodic':obj.periodic, 'discount': obj.discount,'canceled': obj.canceled, 'moved': obj.moved, 'visitors': obj.visitors, 'members': obj.members, 'logo': obj.logo, - 'audience':[item for item, bool in obj.audience if bool==True], + 'audience':[item for item, bool in obj.audience if bool==True], 'org': obj.org, 'quality_label': [item for item, bool in obj.quality_label if bool==True]} if obj.place: @@ -295,4 +295,32 @@ class ConferenceListView(AdminListView): model = Conference def upload_conference_photo(request, conf_id): - return upload_photo(request, conf_id, Conference) \ No newline at end of file + return upload_photo(request, conf_id, Conference) + + +from django.utils import translation +from haystack.query import SearchQuerySet +import json +from exposition.admin import get_by_lang + +def search_conf(request): + term = request.GET['term'].capitalize() + lang = translation.get_language() + if not term: + qs = SearchQuerySet().models(Conference).order_by('text')[:30] + else: + qs = SearchQuerySet().models(Conference).autocomplete(content_auto=term).order_by('text')[:30] + result = [{'id': item.pk, 'label': get_by_lang(item, 'name', lang)} for item in qs] + + return HttpResponse(json.dumps(result), content_type='application/json') + + +def conf_copy(request): + response = {'redirect': ''} + conf = Conference.objects.get(id=request.GET['id']) + duplicate = conf.copy(request.GET['url']) + if isinstance(duplicate, Conference): + response['redirect'] = '/admin/conference/%s/'%duplicate.url + else: + response['msg'] = duplicate + return HttpResponse(json.dumps(response), content_type='application/json') diff --git a/conference/admin_urls.py b/conference/admin_urls.py index 9a206a58..5abc9dd7 100644 --- a/conference/admin_urls.py +++ b/conference/admin_urls.py @@ -5,10 +5,12 @@ from admin import ConferenceListView, ConferenceView urlpatterns = patterns('conference.admin', url(r'^upload-photo/(?P.*)/$', 'upload_conference_photo'), url(r'^delete/(?P.*)$', 'conference_delete'), + url(r'^copy/$', 'conf_copy'), url(r'^all/$', ConferenceListView.as_view()), #url(r'^change/(?P.*)/$', 'conference_change'), url(r'^switch/(?P.*)/(?P.*)$', 'conference_switch'), + url(r'^search/$', 'search_conf'), url(r'^(?P.*)/$', ConferenceView.as_view()), url(r'^$', ConferenceView.as_view()), diff --git a/conference/forms.py b/conference/forms.py index 05f8a0e1..12040fc2 100644 --- a/conference/forms.py +++ b/conference/forms.py @@ -47,9 +47,9 @@ class ConferenceCreateForm(forms.Form): data_end = forms.DateField(label=u'Дата окончания', input_formats=['%Y-%m-%d', '%d.%m.%Y']) logo = forms.ImageField(label='Logo', required=False) - organiser = forms.MultipleChoiceField(label=u'Организаторы', required=False, - choices=[(item.id, item.name) for item in Organiser.objects.language().all()]) - + #organiser = forms.MultipleChoiceField(label=u'Организаторы', required=False, + # choices=[(item.id, item.name) for item in Organiser.objects.language().all()]) + org = forms.CharField(required=False, label=u'Организатор') country = forms.ChoiceField(label=u'Страна', choices=[(c.id, c.name) for c in Country.objects.all()]) theme = forms.MultipleChoiceField(label='Тематики', choices=[(item.id, item.name) for item in Theme.objects.language().all()]) @@ -140,6 +140,7 @@ class ConferenceCreateForm(forms.Form): if data.get('logo'): conference.logo = data['logo'] + conference.org = data['org'] conference.data_begin = data['data_begin'] conference.data_end = data['data_end'] conference.link = data['link'] @@ -375,4 +376,16 @@ class TimeTableForm(forms.Form): class ConferenceFilterForm(AdminFilterForm): - model = Conference \ No newline at end of file + created = forms.DateField(required=False, label='Дата создания') + model = Conference + + def filter(self): + qs = super(ConferenceFilterForm, self).filter() + + data = self.cleaned_data + created = data['created'] + + if created: + + qs = qs.filter(created__startswith=created) + return qs diff --git a/conference/models.py b/conference/models.py index b79b5875..067371db 100644 --- a/conference/models.py +++ b/conference/models.py @@ -5,6 +5,7 @@ from django.db import models from django.db.models import Q from django.db.models.signals import post_save, pre_save from django.contrib.contenttypes import generic +from django.utils import translation from exposition.manager import ClientManager from hvad.models import TranslatableModel, TranslatedFields, TranslationManager from functions.translate import fill_with_signal @@ -53,6 +54,7 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin): related_name='conference_city') place = models.ForeignKey('place_conference.PlaceConference', verbose_name='Место проведения', blank=True, null=True, on_delete=models.PROTECT, related_name='conference_place') + place_alt = models.CharField(blank=True, null=True, max_length=255) # alternative for object place theme = models.ManyToManyField('theme.Theme', verbose_name='Тематики', related_name='conference_themes') tag = models.ManyToManyField('theme.Tag', verbose_name='Теги', @@ -171,6 +173,15 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin): def tags(self): return self.tag.language().all() + def get_index_text(self): + translation.activate('ru') + translations = self.translations.all() + names = ' '.join([tr.name for tr in translations]) + titles = ' '.join([tr.main_title for tr in translations]) + themes = ' '.join([' '.join(theme.get_all_names()) for theme in self.theme.all()]) + tags = ' '.join([' '.join(tag.get_all_names()) for tag in self.tag.all()]) + return names + ' ' + titles + ' ' + themes + ' ' + tags + def get_gallery(self): if self.photogallery: return self.photogallery diff --git a/conference/search_indexes.py b/conference/search_indexes.py index 3266fb52..bdce191b 100644 --- a/conference/search_indexes.py +++ b/conference/search_indexes.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- from haystack import indexes from models import Conference +from functions.search_mixin import ExpoSearchMixin -class ConferenceIndex(indexes.SearchIndex, indexes.Indexable): +class ConferenceIndex(indexes.SearchIndex, indexes.Indexable, ExpoSearchMixin): text = indexes.CharField(document=True, use_template=True) where = indexes.MultiValueField() url = indexes.CharField() @@ -31,13 +32,6 @@ class ConferenceIndex(indexes.SearchIndex, indexes.Indexable): def prepare_catalog_name_ru(self, obj): return u'Конференции' - - def prepare_where(self, obj): - country = [tr.name for tr in obj.country.translations.all()] - city = [tr.name for tr in obj.city.translations.all()] - - return country + city - def get_model(self): return Conference diff --git a/conference/urls.py b/conference/urls.py index 439fa230..77279394 100644 --- a/conference/urls.py +++ b/conference/urls.py @@ -66,6 +66,8 @@ urlpatterns = patterns('', url(r'conference/(?P.*)/members/page/(?P\d+)/$', ConferenceMembers.as_view()), url(r'conference/(?P.*)/members/$', ConferenceMembers.as_view()), url(r'^conference/(?P.*)/service/thanks/', ConferenceThankView.as_view()), + url(r'^conference/(?P.*)/service/visit/', 'conference.views.visit_redirect'), + url(r'conference/(?P.*)/service/(?P.*)/', ConferenceServiceView.as_view()), diff --git a/conference/views.py b/conference/views.py index 3363cc12..c01ce80c 100644 --- a/conference/views.py +++ b/conference/views.py @@ -2,7 +2,7 @@ import json import datetime from django.conf import settings -from django.http import HttpResponse, Http404, HttpResponseRedirect +from django.http import HttpResponse, Http404, HttpResponseRedirect, HttpResponsePermanentRedirect from django.contrib import messages from django.shortcuts import get_object_or_404 from django.contrib.contenttypes.models import ContentType @@ -287,6 +287,12 @@ class ConferenceThankView(MetadataMixin, DetailView): slug_field = 'url' template_name = 'client/service/thank_u_page.html' +def visit_redirect(request, slug): + obj = get_object_or_404(Conference, url=slug) + redirect = obj.get_permanent_url() + return HttpResponsePermanentRedirect(redirect) + + class ConferenceServiceView(FormMixin, DetailView): model = Conference slug_field = 'url' diff --git a/core/simple_views.py b/core/simple_views.py index d6fe480c..5f556f4a 100644 --- a/core/simple_views.py +++ b/core/simple_views.py @@ -13,26 +13,32 @@ class SeminarLendingView(TemplateView): def send_to_organiser(request): - mail_send = 'kotzilla@ukr.net' + mail_send = 'expomap@mail.ru' fname = request.POST.get('name') lname = request.POST.get('surname') email = request.POST.get('email', '') company = request.POST.get('company', '') office = request.POST.get('office', '') + phone = request.POST.get('phone', '') title = request.POST.get('type', '') text = u"""Имя: %s; Фамилия:%s; Email: %s; + Телефон: %s; компния:%s; - должность: %s"""%(fname, lname, email, company, office) + должность: %s"""%(fname, lname, email, phone, company, office) msg = EmailMessage(title, text, settings.DEFAULT_FROM_EMAIL, [mail_send]) msg.content_subtype = "html" msg.send() redirect_to = '/service/thanks/' - message = u"""Мы получили Ваш запрос и очень рады, что Вам интересно участие в семинаре Expomap. Если места еще есть, мы пришлем Вам приглашение на указанную Вами электронную почту. -Увидимся на welcome-coffee ☺""" + if title.endswith(u'семинар'): + message = u"""Мы получили Ваш запрос и очень рады, что Вам интересно участие в семинаре Expomap. Если места еще есть, мы пришлем Вам приглашение на указанную Вами электронную почту. + Увидимся на welcome-coffee ☺""" + else: + message = u"""Благодарим за интерес к нашему семинару! За несколько дней до мероприятия мы пришлем Вам ссылку для подключения к онлайн-трансляции!""" + return HttpResponse(json.dumps({'success':True, 'redirect_to': redirect_to, 'message': message}), content_type='application/json') diff --git a/country/admin.py b/country/admin.py index ede3a8cf..1ad06c86 100644 --- a/country/admin.py +++ b/country/admin.py @@ -63,7 +63,7 @@ def country_change(request, url): if request.POST: #country_id sending for saving capital field in __init__ - form = CountryForm(request.POST, country_id=country_id) + form = CountryForm(request.POST, request.FILES, country_id=country_id) if form.is_valid(): form.save(country_id) @@ -71,8 +71,9 @@ def country_change(request, url): else: #fill form with data from database data = {'population' : c.population, 'teritory' : c.teritory, #data from NOT translated fields - 'timezone' : c.timezone, 'country_id' : country_id, - 'phone_code' : c.phone_code, 'time_delivery' : c.time_delivery} + 'timezone' : c.timezone, 'country_id' : country_id, + 'phone_code' : c.phone_code, 'time_delivery' : c.time_delivery, + 'logo': c.logo} if c.capital: data['capital'] = c.capital.id diff --git a/country/forms.py b/country/forms.py index cdc0be8d..67193e43 100644 --- a/country/forms.py +++ b/country/forms.py @@ -55,6 +55,8 @@ class CountryForm(forms.Form): time_delivery = forms.CharField(label='Срок выдачи', required=False, widget=forms.TextInput(attrs={'placeholder':'Срок выдачи'})) + logo = forms.ImageField(label='Logo', required=False) + #services = forms.MultipleChoiceField(label='Сервисы', required=False, choices=); #field for comparing tmp files key = forms.CharField(required=False, widget=forms.HiddenInput()) @@ -136,6 +138,12 @@ class CountryForm(forms.Form): country.phone_code = data['phone_code'] country.time_delivery = data['time_delivery'] + if data.get('logo'): + country.logo = data['logo'] + else: + country.logo = '' + + if data.get('capital'): country.capital = City.objects.get(id=data['capital']) diff --git a/country/manager.py b/country/manager.py index b267551f..fde5ca56 100644 --- a/country/manager.py +++ b/country/manager.py @@ -93,6 +93,13 @@ class CountryManager(TranslationManager): cache.set(key, countries, self.cache_time) return countries + def countries_for_search(self): + lang = translation.get_language() + qs = super(CountryManager, self).select_related('exposition_country').\ + filter(exposition_country__country__isnull=False, translations__language_code=lang, )\ + .order_by('translations__name').distinct() + return qs + class AreaManager(TranslationManager): def all_sorted(self): diff --git a/country/models.py b/country/models.py index 548d54c7..36bb5a99 100644 --- a/country/models.py +++ b/country/models.py @@ -55,6 +55,12 @@ class Area(TranslatableModel): parent = {} return parent + def get_index_text(self): + translation.activate('ru') + translations = self.translations.all() + names = ' '.join([tr.name for tr in translations]) + return names + class Country(TranslatableModel): """ @@ -102,6 +108,7 @@ class Country(TranslatableModel): descriptions = models.CharField(max_length=255), keywords = models.CharField(max_length=255), ) + logo = models.ImageField(verbose_name='Logo', upload_to='country/logo/', blank=True, max_length=255) class Meta: ordering = ['translations__name'] @@ -145,8 +152,9 @@ class Country(TranslatableModel): return Webinar.objects.filter(country=self.id).count() def active_cities(self): - - return City.used.active_qs().filter(country=self) + result = list(set(City.used.active_qs().filter(country=self))) + result.sort(key=lambda x:x.name) + return result lang = translation.get_language() #return City.objects.select_related('exposition_city')\ # .filter(exposition_city__city__isnull=False, translations__language_code=lang, country=self).distinct().order_by('translations__name') @@ -159,6 +167,12 @@ class Country(TranslatableModel): parent = {'text' : self.area.name, 'id': self.area.id, 'name': 'area'} return parent + def get_index_text(self): + translation.activate('ru') + translations = self.translations.all() + names = ' '.join([tr.name for tr in translations]) + return names + pre_save.connect(pre_save_handler, sender=Country) diff --git a/country/search_indexes.py b/country/search_indexes.py new file mode 100644 index 00000000..0debd42a --- /dev/null +++ b/country/search_indexes.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +from django.utils import translation +from haystack import indexes +from models import Country, Area +from functions.search_mixin import ExpoSearchMixin + + +class CountryIndex(indexes.SearchIndex, indexes.Indexable, ExpoSearchMixin): + text = indexes.CharField(document=True, use_template=True) + url = indexes.CharField() + content_auto = indexes.EdgeNgramField() + form_name = indexes.CharField() + # translated fields + name_en = indexes.CharField() + name_ru = indexes.CharField() + catalog_name_en = indexes.CharField() + catalog_name_ru = indexes.CharField() + + def prepare_form_name(self, obj): + return 'co' + + def prepare_catalog_name_en(self, obj): + return u'Countries' + + def prepare_catalog_name_ru(self, obj): + return u'Страны' + + def get_model(self): + return Country + + def index_queryset(self, using=None): + + return self.get_model().objects.countries_for_search() + + def get_updated_field(self): + return 'modified' + +class AreaIndex(indexes.SearchIndex, indexes.Indexable, ExpoSearchMixin): + text = indexes.CharField(document=True, use_template=True) + content_auto = indexes.EdgeNgramField() + form_name = indexes.CharField() + # translated fields + name_en = indexes.CharField() + name_ru = indexes.CharField() + catalog_name_en = indexes.CharField() + catalog_name_ru = indexes.CharField() + + def prepare_form_name(self, obj): + return 'area' + + def prepare_catalog_name_en(self, obj): + return u'Areas' + + def prepare_catalog_name_ru(self, obj): + return u'Регионы' + + def get_model(self): + return Area + + def index_queryset(self, using=None): + + return self.get_model().objects.filter() \ No newline at end of file diff --git a/expobanner/__init__.py b/expobanner/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/expobanner/admin.py b/expobanner/admin.py new file mode 100644 index 00000000..d1273215 --- /dev/null +++ b/expobanner/admin.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +from django.views.generic import TemplateView, CreateView, ListView, UpdateView +from django.conf import settings +from expobanner.models import URL, BannerGroup, Banner +from expobanner.forms import UrlCreateForm, BannerCreateGroupForm, BannerCreateForm, BannerGroupUpdateForm + + +class BannersControl(TemplateView): + template_name = 'admin/expobanner/banners_control.html' + +# CREATE VIEWS +class AbstractCreate(CreateView): + template_name = 'admin/expobanner/default_form.html' + success_url = '/admin/expobanners/banners/control/' + + +class CreateUrl(AbstractCreate): + model = URL + form_class = UrlCreateForm + + +class CreateBannerGroup(AbstractCreate): + model = BannerGroup + form_class = BannerCreateGroupForm + + +class CreateBanner(AbstractCreate): + model = Banner + form_class = BannerCreateForm + + +# LISTS VIEWS +class AbstractList(ListView): + paginate_by = settings.ADMIN_PAGINATION + template_name = 'admin/expobanner/default_list.html' + + def get_context_data(self, **kwargs): + context = super(AbstractList, self).get_context_data(**kwargs) + context['verbose'] = self.verbose + return context + +class UrlList(AbstractList): + model = URL + verbose = u'Список урлов' + + +class BannerGroupList(AbstractList): + model = BannerGroup + verbose = u'Список груп' + + +class BannerList(AbstractList): + model = Banner + verbose = u'Список банеров' + +# UPDATE VIEWS +class AbstractUpdate(UpdateView): + template_name = 'admin/expobanner/default_form.html' + success_url = '/admin/expobanners/banners/control/' + + +class UrlUpdate(AbstractUpdate): + model = URL + form_class = UrlCreateForm + + +class BannerGroupUpdate(AbstractUpdate): + model = BannerGroup + form_class = BannerGroupUpdateForm + + +class BannerUpdate(AbstractUpdate): + model = Banner + form_class = BannerCreateForm \ No newline at end of file diff --git a/expobanner/admin_urls.py b/expobanner/admin_urls.py new file mode 100644 index 00000000..db31823e --- /dev/null +++ b/expobanner/admin_urls.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +from django.conf.urls import patterns, url +from expobanner.admin import * + +urlpatterns = patterns('expobanner.admin', + url(r'^banners/control/$', BannersControl.as_view(), name='expobanner-baneers_control'), + + url(r'^banners/url/$', CreateUrl.as_view(), name='expobanner-create_url'), + url(r'^banners/group/$', CreateBannerGroup.as_view(), name='expobanner-create_group'), + url(r'^banners/banner/$', CreateBanner.as_view(), name='expobanner-create_banner'), + + url(r'^banners/url/list/$', UrlList.as_view(), name='expobanner-list_url'), + url(r'^banners/group/list/$', BannerGroupList.as_view(), name='expobanner-list_group'), + url(r'^banners/banner/list/$', BannerList.as_view(), name='expobanner-list_banner'), + + url(r'^banners/url/(?P\d+)/edit/$', UrlUpdate.as_view(), name='expobanner-update_url'), + url(r'^banners/group/(?P\d+)/edit/$', BannerGroupUpdate.as_view(), name='expobanner-update_group'), + url(r'^banners/banner/(?P\d+)/edit/$', BannerUpdate.as_view(), name='expobanner-update_banner'), + + +) \ No newline at end of file diff --git a/expobanner/forms.py b/expobanner/forms.py new file mode 100644 index 00000000..64ef9f5a --- /dev/null +++ b/expobanner/forms.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +from django import forms +from expobanner.models import URL, BannerGroup, Banner +from country.models import Country +from city.models import City +from theme.models import Theme, Tag + + +class UrlCreateForm(forms.ModelForm): + verbose = u'Создать урл' + class Meta: + model = URL + exclude = ['created_at', 'updated_at', 'sites'] + + +class BannerCreateGroupForm(forms.ModelForm): + verbose = u'Создать групу' + class Meta: + model = BannerGroup + exclude = ['created_at', 'updated_at', 'speed'] + +class BannerGroupUpdateForm(BannerCreateGroupForm): + verbose = u'Изменить групу' + class Meta: + model = BannerGroup + exclude = ['created_at', 'updated_at', 'slug', 'speed'] + + +class BannerCreateForm(forms.ModelForm): + verbose = u'Создать банер' + country = forms.ChoiceField(label=u'Страна', choices=[('', ' ')] + [(c.id, c.name) for c in Country.objects.all()], required=False) + theme = forms.ChoiceField(label=u'Тематика', required=False, + choices=[('', ' ')] + [(item.id, item.name) for item in Theme.objects.language().all()]) + city = forms.CharField(label=u'Город', widget=forms.HiddenInput(), required=False) + tag = forms.CharField(label=u'Тег', widget=forms.HiddenInput(), required=False) + + + class Meta: + model = Banner + exclude = ['created_at', 'updated_at', 'often', 'paid'] + + def clean_theme(self): + theme = self.cleaned_data['theme'] + if not theme: + return None + try: + return Theme.objects.filter(id=theme) + except Theme.DoesNotExist: + return None + + def clean_country(self): + country = self.cleaned_data['country'] + if not country: + return None + try: + return Country.objects.get(id=country) + except Country.DoesNotExist: + return None + + def clean_tag(self): + tag = self.cleaned_data['tag'] + if not tag: + return None + try: + return Tag.objects.get(id=tag) + except Tag.DoesNotExist: + return None + + def clean_city(self): + city = self.cleaned_data['city'] + if not city: + return None + try: + return City.objects.get(id=city) + except City.DoesNotExist: + return None \ No newline at end of file diff --git a/expobanner/managers.py b/expobanner/managers.py new file mode 100644 index 00000000..a872c61f --- /dev/null +++ b/expobanner/managers.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -* +from random import choice, shuffle +from django.db import models +from django.core.cache import cache + + +class BiasedManager(models.Manager): + def by_time(self, **kwargs): + all = super(BiasedManager, self).get_query_set().filter(**kwargs) + result = [] + for i in all: + for j in range(i.often): + result.append(i) + return result + + def one(self, **kwargs): + return choice(self.by_time(**kwargs)) + + def by_often(self, **kwargs): + result = self.by_time(**kwargs) + shuffle(result) + return result + +class BannerGroupCached(models.Manager): + def all(self): + key = 'banner_group_all' + result = cache.get(key) + if not result: + result = list(self.filter()) + cache.set(key, result, 90) + return result + diff --git a/expobanner/models.py b/expobanner/models.py new file mode 100644 index 00000000..c0e6a6cc --- /dev/null +++ b/expobanner/models.py @@ -0,0 +1,236 @@ +# -*- coding: utf-8 -*- +import hashlib +from datetime import datetime, date + +from django.db import models +from django.utils.translation import ugettext_lazy as _ +from django.conf import settings +from django.contrib.sites.models import Site + +from .managers import BiasedManager, BannerGroupCached + + +class URL(models.Model): + title = models.CharField(verbose_name=u'Заголовок', max_length=256) + url = models.CharField(verbose_name=u'URL or URL RegEx', max_length=2048) + regex = models.BooleanField(verbose_name=u'RegEx', default=False) + sites = models.ManyToManyField(Site, related_name='site_urls', verbose_name=_('Sites'), null=True, blank=True) + + public = models.BooleanField(verbose_name=u'Активный', default=True) + created_at = models.DateTimeField(verbose_name=_('Created At'), auto_now_add=True) + updated_at = models.DateTimeField(verbose_name=_('Updated At'), auto_now=True) + + def __unicode__(self): + return self.title + + class Meta: + ordering = ['-created_at'] + verbose_name = _('URL') + verbose_name_plural = _('URLs') + + def get_admin_url(self): + return '/admin/expobanners/banners/url/%d/edit/'%self.id + + +class BannerGroup (models.Model): + name = models.CharField(verbose_name=u'Имя', max_length=255) + slug = models.SlugField(verbose_name=u'URL', unique=True) + width = models.PositiveSmallIntegerField(verbose_name=u'Ширина', default=0) + height = models.PositiveSmallIntegerField(verbose_name=u'Высота', default=0) + speed = models.PositiveSmallIntegerField(verbose_name=u'Скорость отображения', default=2000) + + public = models.BooleanField(verbose_name=u'Активная', default=True) + created_at = models.DateTimeField(verbose_name=_('Created At'), auto_now_add=True) + updated_at = models.DateTimeField(verbose_name=_('Updated At'), auto_now=True) + cached = BannerGroupCached() + + def size(self): + return '%sx%s' % (self.width, self.height) + + def __unicode__(self): + return '%s - [%s x %s]' % (self.name, self.width, self.height) + + class Meta: + ordering = ['name'] + verbose_name = _('Banner Group') + verbose_name_plural = _('Banner Groups') + + def get_admin_url(self): + return '/admin/expobanners/banners/group/%d/edit/'%self.id + + +class Banner(models.Model): + objects = BiasedManager() + + title = models.CharField(verbose_name=u'Заголовок', max_length=255, blank=True) + alt = models.CharField(verbose_name=_('Alt'), max_length=255) + + text = models.TextField(verbose_name=u'Текст', blank=True, null=True) + img = models.FileField(verbose_name=u'Картинка', upload_to='expo_upload', blank=True, null=True) + url = models.CharField(verbose_name=u'URL', max_length=1024) + + sort = models.PositiveSmallIntegerField(verbose_name=u'Сорт', default=500) + + group = models.ForeignKey(BannerGroup, related_name='banners', verbose_name=u'Место', null=True, blank=True) + often = models.PositiveSmallIntegerField( + verbose_name=_('Often'), + help_text=_('A ten will display 10 times more often that a one.'), + choices=[[i, i] for i in range(11)] + ) + urls = models.ManyToManyField(URL, related_name='url_banners', verbose_name=_('URLs'), null=True, blank=True) + + html = models.BooleanField(verbose_name=_('HTML?'), default=False) + flash = models.BooleanField(verbose_name=_('Flash?'), default=False) + paid = models.BooleanField(verbose_name=_('Is Paid event link?'), default=False) + + + public = models.BooleanField(verbose_name=u'Активный', default=True) + created_at = models.DateTimeField(verbose_name=_('Created At'), auto_now_add=True) + updated_at = models.DateTimeField(verbose_name=_('Updated At'), auto_now=True) + + theme = models.ForeignKey('theme.Theme', blank=True, null=True, verbose_name=u'Тематика') + tag = models.ForeignKey('theme.Tag', blank=True, null=True, verbose_name=u'Тег') + country = models.ForeignKey('country.Country', blank=True, null=True, verbose_name=u'Страна') + city = models.ForeignKey('city.City', blank=True, null=True, verbose_name=u'Город') + + + def get_admin_url(self): + return '/admin/expobanners/banners/banner/%d/edit/'%self.id + + + def key(slef): + if hasattr(settings, 'SECRET_KEY'): + key = str(datetime.now()) + settings.SECRET_KEY + else: + key = str(datetime.now()) + return hashlib.md5(key).hexdigest() + + def log(self, request, type, key): + log = { + 'type': type, + 'key': key, + 'banner': self, + 'group': self.group, + 'ip': request.META.get('REMOTE_ADDR'), + 'user_agent': request.META.get('HTTP_USER_AGENT'), + 'page': request.META.get('HTTP_REFERER'), + } + + if request.user.is_authenticated(): + log['user'] = request.user + return Log.objects.create(**log) + + @models.permalink + def image(self): + return ('banner_view', (), {'banner_id': self.pk, 'key': self.key()}) + + def impressions(self): + return Log.objects.filter(banner=self.pk, type=0).count() + + def views(self): + return Log.objects.filter(banner=self.pk, type=1).count() + + def clicks(self): + return Log.objects.filter(banner=self.pk, type=2).count() + + def __unicode__(self): + return self.title or self.alt + + def get_absolute_url(self): + if self.url == '#': + return self.url + else: + @models.permalink + def get_absolute_url(self): + return ('banner_click', (), {'banner_id': self.pk, 'key': self.key()}) + return get_absolute_url(self) + + class Meta: + ordering = ['sort'] + verbose_name = _('Banner') + verbose_name_plural = _('Banners') + + +class Log(models.Model): + banner = models.ForeignKey(Banner, related_name='banner_logs') + group = models.ForeignKey(BannerGroup, related_name='group_logs', verbose_name=_('Group'), blank=True) + urls = models.ManyToManyField(URL, related_name='url_logs', verbose_name=_('URLs'), blank=True) + + user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, related_name='users', verbose_name=_('User')) + datetime = models.DateTimeField(verbose_name=_('Clicked At'), auto_now_add=True) + ip = models.IPAddressField(verbose_name=_('IP'), null=True, blank=True) + user_agent = models.CharField(verbose_name=_('User Agent'), max_length=1024, null=True, blank=True) + page = models.URLField(verbose_name=_('Page'), null=True, blank=True) + key = models.CharField(verbose_name=_('User Agent'), max_length=32, null=True, blank=True) + TYPE_CHOICES = ( + (0, 'impressions'), + (1, 'view'), + (2, 'click') + ) + + type = models.PositiveSmallIntegerField(verbose_name=_('Type'), max_length=1, default=0, choices=TYPE_CHOICES) + + def __unicode__(self): + return '%s - (%s)' % (self.banner, self.datetime) + + +class LogStat(models.Model): + banner = models.ForeignKey(Banner, related_name='banner_stat', verbose_name=_('Banner'), blank=True) + group = models.ForeignKey(BannerGroup, related_name='group_stat', verbose_name=_('Group'), blank=True) + urls = models.ManyToManyField(URL, related_name='url_bloks', verbose_name=_('URLs'), null=True, blank=True) + + date = models.DateField(verbose_name=_('Data')) + view = models.PositiveIntegerField(verbose_name=_('Views')) + click = models.PositiveIntegerField(verbose_name=_('Clicks')) + unique_click = models.PositiveIntegerField(verbose_name=_('Unique Views'), blank=True, null=True) + unique_view = models.PositiveIntegerField(verbose_name=_('Unique Clicks')) + + def __unicode__(self): + return '%s - (%s)' % (self.banner, self.date) + + +# ------------------ +class Paid(models.Model): + tickets = models.ForeignKey(Banner, related_name='paid_tickets') + participation = models.ForeignKey(Banner, related_name='paid_participation') + official = models.ForeignKey(Banner, related_name='paid_official') + logo = models.ImageField(upload_to='/')# !!!!! + organiser = models.CharField(max_length=100) + active = models.BooleanField(default=True) + stat_pswd = models.CharField(max_length=16) + created = models.DateTimeField(auto_now_add=True) + modified = models.DateTimeField(auto_now=True) + + +class PaidStat(models.Model): + paid = models.ForeignKey(Paid) + date = models.DateField(verbose_name=_('Date')) + page_views = models.PositiveIntegerField(default=0) + price_views = models.PositiveIntegerField(default=0) + catalog_views = models.PositiveIntegerField(default=0) + catalog_clicks = models.PositiveIntegerField(default=0) + + +class Top(models.Model): + catalog = models.CharField(max_length=16) + position = models.PositiveIntegerField(blank=True, null=True) + theme = models.ManyToManyField('theme.Theme', blank=True, null=True) + excluded_tags = models.ManyToManyField('theme.Tag', blank=True, null=True) + country = models.ManyToManyField('country.Country', blank=True, null=True) + excluded_cities = models.ManyToManyField('city.City', blank=True, null=True) + fr = models.DateField(default=date.today()) + to = models.DateField(blank=True, null=True) + stat_pswd = models.CharField(max_length=16) + + class Meta: + ordering = ['position'] + + +class TopStat(models.Model): + date = models.DateField() + theme = models.ForeignKey('theme.Theme', blank=True, null=True) + tag = models.ForeignKey('theme.Tag', blank=True, null=True) + country = models.ForeignKey('country.Country', blank=True, null=True) + city = models.ForeignKey('city.City', blank=True, null=True) + views = models.PositiveIntegerField(default=0) + clicks = models.PositiveIntegerField(default=0) \ No newline at end of file diff --git a/expobanner/static/banners/css/slider.css b/expobanner/static/banners/css/slider.css new file mode 100644 index 00000000..d6d86672 --- /dev/null +++ b/expobanner/static/banners/css/slider.css @@ -0,0 +1,159 @@ +/* + ************************** + * =COMMON + ************************** +*/ +.b-slider { + position: relative; + display: block; + overflow: hidden; + margin: 0; + padding: 0; + width: 725px; + height: 360px; +} + +.b-slider-list { + position: absolute; + display: block; + overflow: hidden; + margin: 0; + padding: 0; + width: 725px; + height: 360px; + list-style: none; +} + +.b-slider-item { + position: absolute; + z-index: 50; + float: left; + overflow: hidden; + margin: 0; + padding: 0; + width: 725px; + height: 360px; +} + +.m-slider-current { + z-index: 100; +} + +.b-slider-item__img, +.b-slider-item__title, +.b-slider-item__text { + position: absolute; +} + +.b-slider-item__img { + top: 0; + left: 0; + text-decoration: none; +} + +.b-slider-item__link { + +} + +.b-slider-item__title { + bottom: 10px; + left: 10px; + width: 500px; + color: #333; + text-transform: uppercase; + text-shadow: 0 0 3px #fff, 0 0 2px #fff, 0 0 1px #fff; + letter-spacing: -5px; + font-size: 65px; + font-family: Calibri; + line-height: 0.8em; +} + +.b-slider-item__text { + position: absolute; + top: 150px; + left: 300px; + display: inline-block; + display: none; + margin: -10px; + padding: 10px; + max-width: 300px; + border-radius: 10px; + background: rgba(255, 255, 255, 0.5); + box-shadow: 0 0 5px #fff; + color: #555; + line-height: 1.5em; +} + + +/* + ************************** + * =NAV + ************************** +*/ +.b-slider-nav { + position: absolute; + width: 100%; + top: 10px; + height: 30px; + left: 0; + z-index: 500; + display: block; + margin: 0; + padding: 0; + list-style-type: none; + text-align: center; +} + +.b-slider-nav-button { + display: inline-block; + margin: 5px; + width: 16px; + height: 16px; + border-radius: 8px; + background: #ddd; + color: transparent; + text-align: center; + font-weight: bold; + font-size: 8px; + line-height: 16px; + cursor: pointer; +} + +.b-slider-nav-button:hover { + background: #eee; +} + +.m-slider-nav-current_button { + background: #fff; +} + +.b-slider-nav-prev, +.b-slider-nav-next { + position: absolute; + top: 0; + z-index: 500; + padding-right: 20px; + padding-left: 20px; + color: #000; + text-shadow: 0 0 3px #fff, 0 0 2px #fff, 0 0 1px #fff; + font-size: 50px; + font-family: Arial, "Helvetica Neue", Helvetica, sans-serif; + line-height: 360px; + opacity: 0.5; + cursor: pointer; +} + +.b-slider-nav-prev:hover, +.b-slider-nav-next:hover { + opacity: 0.8; +} + +.b-slider-nav-prev { + left: 0; + padding-left: 0; +} + +.b-slider-nav-next { + right: 0; + padding-right: 0; +} diff --git a/expobanner/static/banners/js/log.js b/expobanner/static/banners/js/log.js new file mode 100644 index 00000000..eed8e2a1 --- /dev/null +++ b/expobanner/static/banners/js/log.js @@ -0,0 +1,10 @@ + +$(document).ready(function() { + $('.b-banner-click').on('click', function(){ + $.get($(this).data('url')); + }); + + $(".b-banner").on('load', function() { + $.get($(this).data('view')); + }); +}); diff --git a/expobanner/static/banners/js/slider.js b/expobanner/static/banners/js/slider.js new file mode 100644 index 00000000..34769495 --- /dev/null +++ b/expobanner/static/banners/js/slider.js @@ -0,0 +1,71 @@ +$.fn.bannersSlider = function(options) { + $this = this; + var settings = $.extend( { + 'auto_play': false, + 'effect': 'fade', + 'speed' : 3000 + }, options); + + $this.current = 1; + $this.old = 1; + $this.len = $this.find('.b-slider-list li').length; + + $this.find('.b-slider-item').hide(); + $this.find('.m-slider-item-1').show(); + + $this.fadeTo = function(new_num) { + old_num = $this.old; + if (new_num != old_num) { + $this.find('.m-slider-item-' + new_num).hide(); + $this.find('.m-slider-item-' + new_num).fadeIn(1000); + $this.find('.m-slider-current').fadeOut(1000); + $this.find('.m-slider-current').removeClass('m-slider-current'); + $this.find('.m-slider-item-' + new_num).addClass('m-slider-current'); + + $this.find('.b-slider-nav-button').removeClass('m-slider-nav-current_button'); + + $this.find('.b-slider-nav-button[data-slide=' + new_num + ']').addClass('m-slider-nav-current_button'); + } + }; + + $this.prev = function() { + prev = ($this.current != 1) ? $this.current - 1 : $this.len; + $this.old = $this.current; + $this.current = prev; + + $this.fadeTo(prev); + }; + + $this.next = function() { + next = ($this.current != $this.len) ? $this.current + 1 : 1; + $this.old = $this.current; + $this.current = next; + + $this.fadeTo(next); + }; + + $this.children('.b-slider-nav-prev').on('click', function(){ + $this.prev(); + }); + + $this.children('.b-slider-nav-next').on('click', function(){ + $this.next(); + }); + + $this.find('.b-slider-nav-button').on('click', function(){ + to_slide = $(this).data('slide'); + + $this.old = $this.current; + $this.current = to_slide; + + $this.fadeTo(to_slide); + }); + + if (settings.auto_play) { + setInterval(function() { + $this.next(); + }, settings.speed); + } + + return $this; +}; diff --git a/expobanner/templates/banner.html b/expobanner/templates/banner.html new file mode 100644 index 00000000..85f460e1 --- /dev/null +++ b/expobanner/templates/banner.html @@ -0,0 +1,55 @@ +{% if banner.html %} + {% load banner %} + +{% elif banner.flash %} + + + +{% else %} + +{% endif %} + + \ No newline at end of file diff --git a/expobanner/templates/grid.html b/expobanner/templates/grid.html new file mode 100644 index 00000000..9571fd2d --- /dev/null +++ b/expobanner/templates/grid.html @@ -0,0 +1,32 @@ +{% load banner %} + +
+ {% for banner in banners %} + {% banner_one banner.id %} + {% endfor %} +
+ + \ No newline at end of file diff --git a/expobanner/templates/group.html b/expobanner/templates/group.html new file mode 100644 index 00000000..36800ccc --- /dev/null +++ b/expobanner/templates/group.html @@ -0,0 +1,30 @@ +{% load banner %} + +
+ {% for banner in banners %} + {% banner_one banner.id %} + {% endfor %} + +
\ No newline at end of file diff --git a/expobanner/templates/slider.html b/expobanner/templates/slider.html new file mode 100644 index 00000000..fcd6bd12 --- /dev/null +++ b/expobanner/templates/slider.html @@ -0,0 +1,74 @@ +{% load thumbnail %} + +{% if banners %} + +
+ + +
    + {% for banner in banners %} +
  • + {{ forloop.counter }} +
  • + {% endfor %} +
+ + 〈   +   〉 + +
+ + + + + +{% endif %} \ No newline at end of file diff --git a/expobanner/templatetags/__init__.py b/expobanner/templatetags/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/expobanner/templatetags/banner.py b/expobanner/templatetags/banner.py new file mode 100644 index 00000000..c1491a74 --- /dev/null +++ b/expobanner/templatetags/banner.py @@ -0,0 +1,74 @@ +from ..models import Banner +from ..models import BannerGroup +from ..models import URL + +from django import template + +# For render tag +from django.template import Context +from django.template import Template + +import re + +register = template.Library() + + +@register.simple_tag(takes_context=True) +def banner_group(context, group, tpl='group.html'): + try: + page_url = context['request'].path_info + site = context['request'].site + group = BannerGroup.objects.get(slug=group) + good_urls = [] + for url in URL.objects.filter(public=True, sites__in=[site]): + if url.regex: + url_re = re.compile(url.url) + if url_re.findall(page_url): + good_urls.append(url) + elif page_url == url.url: + good_urls.append(url) + banners = Banner.objects.filter(public=True, group=group, urls__in=good_urls) + except: + banners = False + group = False + if(banners and group): + context['banners'] = banners + context['group'] = group + + t = template.loader.get_template(tpl) + return t.render(template.Context(context)) + + +@register.simple_tag(takes_context=True) +def banner_one(context, banner_id, tpl='banner.html'): + try: + page_url = context['request'].path_info + site = context['request'].site + good_urls = [] + for url in URL.objects.filter(public=True, sites__in=[site]): + if url.regex: + url_re = re.compile(url.url) + if url_re.findall(page_url): + good_urls.append(url) + elif page_url == url.url: + good_urls.append(url) + + banner = Banner.objects.get(id=banner_id, public=True, urls__in=good_urls) + except: + banner = False + + context['banner'] = banner + + t = template.loader.get_template(tpl) + return t.render(template.Context(context)) + + +# block render +@register.simple_tag(takes_context=True) +def render(context, content): + try: + tpl = Template(content) + content = Context(context) + return tpl.render(content) + except: + return 'Render Error' diff --git a/expobanner/tests.py b/expobanner/tests.py new file mode 100644 index 00000000..501deb77 --- /dev/null +++ b/expobanner/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.assertEqual(1 + 1, 2) diff --git a/expobanner/urls.py b/expobanner/urls.py new file mode 100644 index 00000000..4371bc5f --- /dev/null +++ b/expobanner/urls.py @@ -0,0 +1,11 @@ +from django.conf.urls import url + +from . import views + +urlpatterns = [ + url(r'^click/(?P\d{1,4})/(?P[-\w]+)/$', views.click, name='banner_click'), + url(r'^view/(?P\d+)/(?P[-\w]+)/$', views.view, name='banner_view'), + + # + url(r'^get-banners/$', views.get_banners), +] diff --git a/expobanner/views.py b/expobanner/views.py new file mode 100644 index 00000000..94709042 --- /dev/null +++ b/expobanner/views.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +import json +from django.http import HttpResponse +from django.shortcuts import redirect, get_object_or_404 +from .models import Banner, BannerGroup + + +def click(request, banner_id, key): + banner = get_object_or_404(Banner, pk=banner_id) + banner.log(request, 2, key) + return redirect(banner.url) + + +def view(request, banner_id, key): + banner = get_object_or_404(Banner, pk=banner_id) + banner.log(request, 1, key) + return redirect(banner.img.url) + + +def get_client_ip(request): + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + if x_forwarded_for: + ip = x_forwarded_for.split(',')[0] + else: + ip = request.META.get('REMOTE_ADDR') + return ip + +def get_banners(request): + url = request.GET.get('url', '/') + theme = request.GET.get('theme') + country = request.GET.get('country') + city = request.GET.get('city') + tag = request.GET.get('tag') + ip = get_client_ip(request) + params = {'url': url, + 'theme': theme, + 'tag': tag, + 'country': country, + 'city': city, + 'ip': ip} + b = Banner.objects.get(id=1) + result = [{'url': b.url, 'id': 'expo_b_%d'%b.id, 'is_html': b.html, + 'is_flash': b.flash, 'is_img': True, 'html': b.text, 'img': b.img.url}] + return HttpResponse(json.dumps(result, indent=4), content_type='application/json') + + diff --git a/exposition/admin.py b/exposition/admin.py index 7bdf2d09..0345864a 100644 --- a/exposition/admin.py +++ b/exposition/admin.py @@ -277,7 +277,7 @@ class ExpositionView(AdminView): 'min_stand_size':obj.min_stand_size, 'application_deadline':obj.application_deadline, 'min_open_area':obj.min_open_area, 'max_open_area':obj.max_open_area, 'registration_payment':obj.registration_payment, 'exposition_id':obj.id, - 'registration_link': obj.registration_link, + 'registration_link': obj.registration_link, 'org': obj.org, 'expohit': obj.expohit, 'discount': obj.discount, 'canceled': obj.canceled, 'moved': obj.moved, 'logo': obj.logo, 'visitors': obj.visitors, 'members': obj.members, @@ -404,3 +404,12 @@ class PaidView(FormView): +def expo_copy(request): + response = {'redirect': ''} + expo = Exposition.objects.get(id=request.GET['id']) + duplicate = expo.copy(request.GET['url']) + if isinstance(duplicate, Exposition): + response['redirect'] = '/admin/exposition/%s/'%duplicate.url + else: + response['msg'] = duplicate + return HttpResponse(json.dumps(response), content_type='application/json') diff --git a/exposition/admin_urls.py b/exposition/admin_urls.py index 096b5444..7b521cb3 100644 --- a/exposition/admin_urls.py +++ b/exposition/admin_urls.py @@ -4,6 +4,7 @@ from admin import ExpositionListView, ExpositionView, PaidView urlpatterns = patterns('exposition.admin', url(r'^upload-photo/(?P.*)/$', 'upload_exposition_photo'), + url(r'^copy/$', 'expo_copy'), url(r'^(?P.*)/paid/$', PaidView.as_view()), #url(r'^add.*/$', 'exposition_add'), diff --git a/exposition/forms.py b/exposition/forms.py index d588c80d..990fc457 100644 --- a/exposition/forms.py +++ b/exposition/forms.py @@ -49,11 +49,12 @@ class ExpositionCreateForm(forms.Form): data_end = forms.DateField(label=u'Дата окончания', input_formats=['%Y-%m-%d', '%d.%m.%Y']) logo = forms.ImageField(label='Logo', required=False) - organiser = forms.MultipleChoiceField(label=u'Организаторы', required=False, - choices=[(item.id, item.name) for item in Organiser.objects.language().all()]) + #organiser = forms.MultipleChoiceField(label=u'Организаторы', required=False, + # choices=[(item.id, item.name) for item in Organiser.objects.language().all()]) + org = forms.CharField(required=False, label=u'Организатор') - company = forms.MultipleChoiceField(label=u'Компании', required=False, - choices=[(item.id, item.name) for item in Company.objects.language().all()] ) + #company = forms.MultipleChoiceField(label=u'Компании', required=False, + # 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.all()]) theme = forms.MultipleChoiceField(label='Тематики', choices=[(item.id, item.name) for item in Theme.objects.language().all()]) @@ -62,7 +63,6 @@ class ExpositionCreateForm(forms.Form): #creates select input with empty choices cause it will be filled with ajax city = forms.CharField(label=u'Город', widget=forms.HiddenInput()) tag = forms.CharField(label=u'Теги', widget=forms.HiddenInput(), required=False) - #tag = forms.MultipleChoiceField(label=u'Теги', required=False) periodic = forms.ChoiceField(label=u'Периодичность', choices=PERIODIC, required=False) audience = forms.MultipleChoiceField(label=u'Аудитория', choices=public, initial='', required=False) @@ -169,7 +169,7 @@ class ExpositionCreateForm(forms.Form): exposition.theme.clear() exposition.tag.clear() exposition.organiser.clear() - exposition.company.clear() + #exposition.company.clear() #simple fields if not getattr(exposition, 'url'): @@ -177,6 +177,7 @@ class ExpositionCreateForm(forms.Form): if data.get('logo'): exposition.logo = data['logo'] + exposition.org = data['org'] exposition.data_begin = data['data_begin'] exposition.data_end = data['data_end'] exposition.periodic = data['periodic'] @@ -236,7 +237,7 @@ class ExpositionCreateForm(forms.Form): exposition.theme.add(*data['theme']) exposition.tag.add(*Tag.objects.filter(id__in=data['tag'])) exposition.organiser.add(*Organiser.objects.filter(id__in=data.get('organiser', []))) - exposition.company.add(*Company.objects.filter(id__in=data.get('company', []))) + #exposition.company.add(*Company.objects.filter(id__in=data.get('company', []))) exposition.save() diff --git a/exposition/management/commands/test.py b/exposition/management/commands/test.py index 271b6d8d..022c3e6d 100644 --- a/exposition/management/commands/test.py +++ b/exposition/management/commands/test.py @@ -1,20 +1,141 @@ # -*- coding: utf-8 -*- +import MySQLdb +import os.path +from MySQLdb.cursors import DictCursor +from django.utils.translation import activate from django.core.management.base import BaseCommand -from meta.models import MetaSetting +from django.conf import settings +from exposition.models import Exposition +from theme.models import Theme +from theme.models import Theme, Tag class Command(BaseCommand): def handle(self, *args, **options): - a = MetaSetting.objects.filter(translations__h1__contains='«').count() - qs = MetaSetting.objects.language('ru').all() - for item in qs: - item.title = item.title.replace(u'«', u'').replace(u'»', u'') - item.description = item.title.replace(u'«', u'').replace(u'»', u'') - item.h1 = item.h1.replace(u'«', u'').replace(u'»', u'') - #item.save() + #expos = Exposition.objects.filter(theme__isnull=True, old_url__isnull=False) + db = MySQLdb.connect(host="localhost", + user="expomap", + passwd="7FbLtAGjse", + db="old_db", + charset='utf8', + cursorclass=DictCursor) + cursor = db.cursor() + activate('ru') + #expos = Exposition.enable.upcoming().filter(logo='') + expos = Exposition.objects.filter(tag__isnull=True).order_by('-data_end') + #expo = Exposition.objects.get(old_url='salon-du-livre-2015') + #handle_expo_tag(expo, cursor) + for expo in expos: + handle_expo_tag(expo, cursor) + + ''' + find_old_id = """ + SELECT products.products_id + from products + LEFT JOIN `products_description` ON products.products_id=products_description.products_id + WHERE url='%s' + """ + + find_themes = "SELECT categories_id FROM `products_to_categories` WHERE `products_id` =%d" + ''' + """ + for expo in expos: + cursor.execute(find_old_id%expo.old_url) + old_ids = [item['products_id'] for item in cursor.fetchall()] + print expo.old_url + for id in old_ids: + cursor.execute(find_themes%id) + themes_ids = [item['categories_id'] for item in cursor.fetchall()] + print themes_ids + #if not themes_ids: + # continue + + + theme_qs = Theme.objects.filter(id__in=themes_ids) + #expo.theme.add(*theme_qs) + break + + print('----------------------') + """ + + +def handle_expo_tag(expo, cursor): + old_url = expo.old_url + if not old_url: + return None + print(old_url) + find_old = """ + SELECT products.products_id, url + from products + LEFT JOIN `products_description` ON products.products_id=products_description.products_id + WHERE url='%s' + """ + cursor.execute(find_old%old_url) + result = cursor.fetchone() + expo_id = result.get('products_id') + if not expo_id: + return + + find_tag_id = """ + SELECT tag_id + FROM `products_tags` + WHERE `product_id` =%d + """ + cursor.execute(find_tag_id%expo_id) + tags_ids = [str(item['tag_id']) for item in cursor.fetchall()] + if not tags_ids: + return None + find_tag = """ + SELECT title + FROM `tags` + WHERE id in(%s) + """ + cursor.execute(find_tag%', '.join(tags_ids)) + tag_names = [item['title'] for item in cursor.fetchall()] + if not tag_names: + return None + + themes = [item['id'] for item in expo.theme.all().values('id')] + qs = Tag.objects.filter(translations__name__in=tag_names, theme__in=themes) + expo.tag.add(*qs) + + + +def handle_expo(expo, cursor): + """ + fixing logos + + """ + if expo.logo: + return + + find_old = """ + SELECT products.products_id, url, products_img1 as logo + from products + LEFT JOIN `products_description` ON products.products_id=products_description.products_id + WHERE url='%s' + """ + cursor.execute(find_old%expo.old_url) + result = cursor.fetchall() + if not result: + return + logo = result[0]['logo'] + + + if logo: + logo = logo.replace('..', '') + + print(logo) + print(os.path.isfile(settings.MEDIA_ROOT[:-1]+logo)) + if (os.path.isfile(settings.MEDIA_ROOT[:-1]+logo)): + + expo.logo = logo + expo.save() + + diff --git a/exposition/models.py b/exposition/models.py index 77fb9c4d..dce42537 100644 --- a/exposition/models.py +++ b/exposition/models.py @@ -72,6 +72,7 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): organiser = models.ManyToManyField('organiser.Organiser', verbose_name='Организатор', blank=True, null=True, related_name='exposition_organisers') org = models.CharField(max_length=255, blank=True, null=True) + place_alt = models.CharField(max_length=255, blank=True, null=True) company = models.ManyToManyField('company.Company', verbose_name='Компании', blank=True, null=True, related_name='exposition_companies') users = models.ManyToManyField('accounts.User', verbose_name='Посетители выставки', @@ -299,6 +300,9 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): return code return cur + def theme_ids(self): + return [item['id'] for item in self.theme.all().values('id')] + class Statistic(TranslatableModel): exposition = models.ForeignKey(Exposition, related_name='statistic') diff --git a/exposition/search_indexes.py b/exposition/search_indexes.py index 4ef91e7f..0a427eb7 100644 --- a/exposition/search_indexes.py +++ b/exposition/search_indexes.py @@ -40,15 +40,5 @@ class ExpositionIndex(indexes.SearchIndex, indexes.Indexable, ExpoSearchMixin): return self.get_model().objects.filter(is_published=True) - def get_name(self): - return 123 - lang = translation.get_language() - if lang == 'ru': - return self.name_ru - elif lang=='en': - return self.name_en - else: - return self.name_ru - def get_updated_field(self): return 'modified' \ No newline at end of file diff --git a/exposition/urls.py b/exposition/urls.py index cad06b17..5290ea71 100644 --- a/exposition/urls.py +++ b/exposition/urls.py @@ -72,6 +72,7 @@ urlpatterns = patterns('', url(r'^expo/(?P.*)/members/page/(?P\d+)/$', ExpoMembers.as_view(), {'meta_id':63}), url(r'^expo/(?P.*)/members/$', ExpoMembers.as_view(), {'meta_id':63}), url(r'^expo/(?P.*)/service/thanks/', ExpositionThankView.as_view()), + url(r'^expo/(?P.*)/service/visit/', 'exposition.views.visit_redirect'), url(r'^expo/(?P.*)/service/(?P.*)/', ExpositionServiceView.as_view()), # expo list url(r'^expo/(?P\d+)/(?P.*)/page/(?P\d+)/$', ExpoList.as_view(), {'meta_id':4}), diff --git a/exposition/views.py b/exposition/views.py index 98dac122..48b55b3b 100644 --- a/exposition/views.py +++ b/exposition/views.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import json import datetime -from django.http import HttpResponseRedirect, HttpResponse +from django.http import HttpResponseRedirect, HttpResponse, HttpResponsePermanentRedirect from django.contrib import messages from django.contrib.contenttypes.models import ContentType from django.conf import settings @@ -182,6 +182,11 @@ class ExpositionThankView(MetadataMixin, DetailView): slug_field = 'url' template_name = 'client/service/thank_u_page.html' +def visit_redirect(request, slug): + obj = get_object_or_404(Exposition, url=slug) + redirect = obj.get_permanent_url() + 'price/' + return HttpResponsePermanentRedirect(redirect) + class ExpositionServiceView(MetadataMixin, FormMixin, DetailView): model = Exposition slug_field = 'url' @@ -289,7 +294,7 @@ MONTHES = settings.MONTHES class ExpoCatalog(MetadataMixin, ListView): model = Exposition paginate_by = settings.CLIENT_PAGINATION - template_name = 'exposition/catalog.html' + template_name = 'client/exposition/catalog.html' search_form = ExpositionSearchForm filter_object = None year = None @@ -440,6 +445,12 @@ class ExpoTagCatalog(ExpoCatalog): self.filter_object = tag return qs + def get_context_data(self, **kwargs): + context = super(ExpoTagCatalog, self).get_context_data(**kwargs) + tag = self.kwargs['tag'] + context['theme_for_filter'] = tag.theme + return context + class ExpoVisitors(MetadataMixin, ListView): paginate_by = settings.CLIENT_PAGINATION diff --git a/functions/form_check.py b/functions/form_check.py index e8c0954e..cfbe998f 100644 --- a/functions/form_check.py +++ b/functions/form_check.py @@ -31,10 +31,15 @@ def translit_with_separator(string, separator='-'): #make string unicode string = string.strip() string = u'%s'%string - string = string.replace(u'\u200e', '') #make string translit - st = pytils.translit.translify(string) + try: + st = pytils.translit.translify(string) + except ValueError: + # remove exception symbs(hack) + string = string.replace(u'\u200e', '') + string = string.replace(u'\u200b', '') + st = pytils.translit.translify(string) #replace "bad" symbols for '-'symbol st = st.replace('.', '') diff --git a/functions/model_mixin.py b/functions/model_mixin.py index 36b120b4..a96c53cc 100644 --- a/functions/model_mixin.py +++ b/functions/model_mixin.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- +import copy import calendar as python_calendar from service.models import Service @@ -32,8 +34,11 @@ class EventMixin(object): url = '%s%s/'%(self.get_catalog_url(), self.url) return url - - + def org_split(self): + if self.org: + return self.org.split(';') + else: + return [] def get_logo(self): return self.logo @@ -98,4 +103,43 @@ class EventMixin(object): if self.data_end.month == month: return self.data_end.day - return 0 \ No newline at end of file + return 0 + + def copy(self, url): + """ + Copy event with new url + :param url: new url for event + :return: event object + """ + # check url + Model = type(self) + try: + Model.objects.get(url=url) + return u'Событие с таким урлом уже существует' + except Model.DoesNotExist: + pass + + duplicate = copy.copy(self) + duplicate.url = url + # Setting pk to None. for Django its a new object. + duplicate.pk = None + # copy translations + ignore_fields = ['id', 'master', 'language_code'] + duplicate.translate('ru') + tr = self._meta.translations_model.objects.get(language_code='ru', master__id=self.pk) + for field in duplicate._translated_field_names: + if field in ignore_fields: + continue + + setattr(duplicate, field, getattr(tr, field)) + duplicate.is_published = False + duplicate.save() # save but lost all ManyToMany relations + + # copy relations + for field in self._meta.many_to_many: + source = getattr(self, field.attname) + destination = getattr(duplicate, field.attname) + for item in source.all(): + destination.add(item) + + return duplicate \ No newline at end of file diff --git a/functions/search_forms.py b/functions/search_forms.py index 30158eda..5faea6e0 100644 --- a/functions/search_forms.py +++ b/functions/search_forms.py @@ -278,7 +278,7 @@ class ExpositionSearchForm(AbstactSearchForm): area = self.cleaned_data.get('area') - sqs = SearchQuerySet().models(Exposition).all() + sqs = SearchQuerySet().models(Exposition, Conference).all() if fr: sqs = sqs.filter(data_begin__gte=fr) diff --git a/import_xls/admin.py b/import_xls/admin.py index 2de38d12..8fa890f5 100644 --- a/import_xls/admin.py +++ b/import_xls/admin.py @@ -13,8 +13,10 @@ from import_forms import ImportEventForm, ImportThemeForm, ImportTagForm, Import from export_forms import ExportEventForm, ExportOrganiserForm, ExportThemeForm, ExportTagForm,\ ExportUserForm, ExportCompanyForm, ExportPlaceConferenceForm, ExportPlaceExpositionForm, ExportBlogForm,\ ExportCityForm -from django.views.generic import FormView +from django.views.generic import FormView, ListView, DeleteView +from django.conf import settings from django.contrib import messages +from django.shortcuts import get_object_or_404 def xls_to_response(xls, fname): response = HttpResponse(mimetype="application/ms-excel") @@ -93,20 +95,23 @@ class ExportCity(ExportView): -from exposition.models import Exposition +from import_xls.models import Log class ImportEvent(FormView): form_class = ImportEventForm success_url = '/admin/import-event/' template_name = 'admin/import templates/import_event.html' def form_valid(self, form): + errors = form.save_file_debug() - messages.success(self.request, 'Success') - context = self.get_context_data() - context['import_errors'] = errors - context['form'] = form - return render_to_response(self.template_name, context) + return HttpResponseRedirect('/admin/import/log/') + + #messages.success(self.request, 'Success') + + #context = self.get_context_data() + #context['import_errors'] = errors + #context['form'] = form + #return render_to_response(self.template_name, context) - #return super(ImportEvent, self).form_valid(form) class ImportTheme(ImportView): form_class = ImportThemeForm @@ -131,4 +136,34 @@ class ImportPlaceConference(ImportView): class ExportEvent(ExportView): form_class = ExportEventForm template_name = 'export_event.html' - success_url = '/admin/export-event' \ No newline at end of file + success_url = '/admin/export-event' + + +class LogList(ListView): + model = Log + paginate_by = settings.ADMIN_PAGINATION + template_name = 'admin/import templates/log.html' + +class LogDelete(DeleteView): + model = Log + success_url = '/admin/import/log/' + template_name = 'admin/import templates/log_delete.html' + + +def log_file(request, log_id): + log = get_object_or_404(Log, id=log_id) + response = HttpResponse() + response['content-type'] = 'application/x-executable' + filename = 'import_%s_log.txt'%str(log.id) + response['content-disposition'] = 'attachment;filename=%s'%filename + response['X-Accel-Redirect'] = log.log.url + return response + +def work_file(request, log_id): + log = get_object_or_404(Log, id=log_id) + response = HttpResponse() + response['content-type'] = 'application/x-executable' + filename = 'import_%s_file.xls'%str(log.id) + response['content-disposition'] = 'attachment;filename=%s'%filename + response['X-Accel-Redirect'] = log.work_file.url + return response diff --git a/import_xls/admin_urls.py b/import_xls/admin_urls.py index baf65303..0d7af157 100644 --- a/import_xls/admin_urls.py +++ b/import_xls/admin_urls.py @@ -2,8 +2,11 @@ from django.conf.urls import patterns, url from admin import ImportTheme, ImportEvent, ImportOrganiser, ImportTag, ImportPlaceExposition, ImportPlaceConference + from admin import ExportTheme, ExportEvent, ExportOrganiser, ExportTag, ExportPlaceExposition,\ - ExportPlaceConference, ExportCompany, ExportUser, ExportBlog, ExportCity + ExportPlaceConference, ExportCompany, ExportUser, ExportBlog, ExportCity, LogList +from import_xls.admin import LogDelete + urlpatterns = patterns('', url(r'^import-event/$', ImportEvent.as_view()), @@ -23,5 +26,8 @@ urlpatterns = patterns('', url(r'^export-company/$', ExportCompany.as_view()), url(r'^export-blog/$', ExportBlog.as_view()), url(r'^export-city/$', ExportCity.as_view()), + url(r'^import/log/$', LogList.as_view()), + url(r'^import/log/delete/(?P.*)/$', LogDelete.as_view()), + url(r'^log/log/(?P.*)/$', 'import_xls.admin.log_file'), + url(r'^log/work_file/(?P.*)/$', 'import_xls.admin.work_file'), ) - diff --git a/import_xls/excel_settings.py b/import_xls/excel_settings.py index 94cab89f..71c53b6f 100644 --- a/import_xls/excel_settings.py +++ b/import_xls/excel_settings.py @@ -45,11 +45,6 @@ def get_periodic(value): return periodic.get(value, '') return '' -def get_date(value): - if value: - return str(value) - return '' - def get_quality(value, field): flags = {u'UFI': 'ufi', u'РСВЯ': 'rsva', u'EXPORATING': 'exporating'} v = flags.get(field) @@ -326,19 +321,27 @@ article_sett = { u'Создана':{u'field': u'created', u'func': to_datetime} } +def get_date(value): + try: + return value.strftime('%d.%m.%Y') + except AttributeError: + return '' + + event_export_sett = [ {'name': 'id', 'verbose_name': u'ID', 'type': get_int, 'width':1500}, {'name': 'url', 'verbose_name': u'Url', 'type': unicode}, {'name': 'name', 'verbose_name': u'Название', 'type': unicode}, {'name': 'main_title', 'verbose_name': u'Краткое описание', 'type': unicode}, - {'name': 'data_begin', 'verbose_name': u'Дата начала:(YYYY-MM-DD)', 'type': unicode}, - {'name': 'data_end', 'verbose_name': u'Дата окончания:(YYYY-MM-DD)', 'type': unicode}, + {'name': 'data_begin', 'verbose_name': u'Дата начала:(YYYY-MM-DD)', 'type': get_date}, + {'name': 'data_end', 'verbose_name': u'Дата окончания:(YYYY-MM-DD)', 'type': get_date}, {'name': 'country', 'verbose_name': u'Страна', 'type': unicode}, {'name': 'city', 'verbose_name': u'Город', 'type': unicode}, {'name': 'place', 'verbose_name': u'Место проведения', 'type': get_place}, {'name': 'theme', 'verbose_name': u'ID Тематики', 'type': get_theme, 'width':8000}, {'name': 'tag', 'verbose_name': u'Теги', 'type': get_tag, 'width':8000}, {'name': 'description', 'verbose_name': u'Описание события', 'type': unicode}, + {'name': 'org', 'verbose_name': u'Организатор №1', 'type': get_int}, {'name': 'periodic', 'verbose_name': 'Периодичность', 'type': get_periodic}, {'name': 'audience', 'verbose_name': u'Аудитория', 'type': get_audience}, {'name': 'web_page', 'verbose_name': u'Официальный веб-сайт', 'type': unicode}, @@ -500,6 +503,8 @@ event_sett = { u'Участники':{u'field': u'members', u'func': to_int}, u'Страны':{u'field': u'stat_countries', u'func': unicode}, u'Площадь':{u'field': u'area', u'func': to_int}, + u'Мин стоимость':{u'field': u'min_price', u'func': to_int}, + u'Макс стоимость':{u'field': u'max_price', u'func': to_int}, u'Min_Raw кв.м.':{u'field': u'min_closed_area', u'func': to_int}, u'Max_Raw кв.м.':{u'field': u'max_closed_area', u'func': to_int}, u'Min_Pack кв.м.':{u'field': u'min_closed_equipped_area', u'func': to_int}, diff --git a/import_xls/import_forms.py b/import_xls/import_forms.py index 27f83514..9e36895e 100644 --- a/import_xls/import_forms.py +++ b/import_xls/import_forms.py @@ -106,6 +106,7 @@ def google_address(address): response = {'address' : results[0].get('formatted_address'), 'lat' : results[0]['geometry']['location']['lat'], 'lng' : results[0]['geometry']['location']['lng']} + #return response return json.dumps(response) else: return '' @@ -113,11 +114,11 @@ def google_address(address): from djutils.decorators import async from djutils.queue.decorators import queue_command - +# place class ImportPlaceExpositionForm(ImportForm): model = PlaceExposition settings = place_exp_sett - #@async + def save_file(self): data = self.cleaned_data lang = data['language'] @@ -125,86 +126,113 @@ class ImportPlaceExpositionForm(ImportForm): book = xlrd.open_workbook(file_contents=f.read()) sheet = book.sheet_by_index(0) row_list = [sheet.row_values(row_number) for row_number in range(sheet.nrows)] + model = self.model labels = [label for label in row_list[0]] + errors = [] for row_number, row in enumerate(row_list): + if row_number == 0: + continue + if row[0] != '': + # in first column id + try: + obj = self.model.objects.language(lang).get(id=int(row[0])) + except ValueError: + obj = self.model() + obj.translate(lang) + + except self.model.DoesNotExist: + obj = self.model(id= int(row[0])) + obj.translate(lang) + else: + # if id blank - its a new event + obj = model() + obj.translate(lang) + # ---------------- # go through all rows in file - if row_number > 0: - # first field is label - if row[0] != '': - # in first column ids + methods = [] + for col_number, cell in enumerate(row): + # go through row cells + # field name current cell + label = labels[col_number] + setting = place_exp_sett.get(label) + + if setting is None: + continue + + if setting.get('method'): + if cell != "": + methods.append({'func': setting['func'], 'value': cell, 'purpose': setting.get('purpose')}) + continue + + field_name = setting['field'] + + func = setting.get('func') + if func is None: + continue + + extra_value = setting.get('extra_values') + if extra_value is not None: + # if setting has extra value then + # it is some field like city, theme, tag + # that has relation and can be created + + # in function we add language(need for relation fields) + # and extra value from object (like for city need country) try: - object = self.model.objects.language(lang).get(id=int(row[0])) - except ValueError: - object = self.model() - object.translate(lang) + extra = getattr(obj, extra_value) + except Exception: + continue + value = func(cell, 'ru', extra) - except self.model.DoesNotExist: - object = self.model(id= int(row[0])) - object.translate(lang) else: - # if id blank - its a new event - object = self.model() - object.translate(lang) - methods = [] - for col_number, cell in enumerate(row): - # go through row cells - # field name current cell - label = labels[col_number] - setting = place_exp_sett.get(label) + value = func(cell) - if setting is None: - continue + try: + setattr(obj, field_name, value) + except ValueError, e: + continue - if setting.get('method'): - if cell != "": - methods.append({'func': setting['func'], 'value': cell, 'purpose': setting.get('purpose')}) + if field_name !='adress': + try: + setattr(obj, field_name, value) + except ValueError: continue - field_name = setting['field'] + else: + #gaddress = google_address(value) + setattr(obj, 'address', google_address(value)) + + if not obj.url: + obj.url = translit_with_separator(obj.name) + try: + obj.save() + except IntegrityError, e: - func = setting.get('func') - if func is not None: - extra_value = setting.get('extra_values') - if extra_value is not None: - # if setting has extra value then - # it is some field like city, theme, tag - # that has relation and can be created + error = str(e) + if typical_errors.get(error): + error = typical_errors[error] + if error.startswith('(1062, "Duplicate entry') and error.endswith('for key \'url\'")'): + error = u'Место с таким названием или урлом уже существует' - # in function we add language(need for relation fields) - # and extra value from object (like for city need country) - value = func(cell, lang, getattr(object, extra_value)) - else: - value = func(cell) - if field_name =='adress': - setattr(object, 'address', google_address(value)) - setattr(object, field_name, value) + errors.append([obj.name, error]) + continue + for method in methods: + func = method['func'] + if method.get('purpose'): + try: + func(obj, method['value'], method['purpose']) + except Exception, e: + continue + else: + func(obj, method['value']) - try: - object.save() + return errors - except IntegrityError: - continue - #url = object.url + translit_with_separator(object.city.name) - #object.url = url - #object.save() - - for method in methods: - func = method['func'] - if method.get('purpose'): - try: - func(object, method['value'], method['purpose']) - except: - continue - else: - try: - func(object, method['value']) - except: - continue class ImportPlaceConferenceForm(ImportForm): @@ -217,6 +245,16 @@ typical_errors = {'(1048, "Column \'city_id\' cannot be null")':u'Неправи '(1048, "Column \'data_end\' cannot be null")':u'НЕправильный формат или не заполнена дата окончания', '(1048, "Column \'data_end\' cannot be null")':u'НЕправильный формат или не заполнена дата начала'} +# event +import time +def logcall(f, msg): + with open(f.file.name, 'a') as logfile: + logfile.write(msg.encode('utf8')) + + + + +from import_xls.models import Log class ImportEventForm(ImportForm): """ extended form for importing one type of event diff --git a/import_xls/models.py b/import_xls/models.py new file mode 100644 index 00000000..8bb0d818 --- /dev/null +++ b/import_xls/models.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +from django.db import models +from django.conf import settings +from django.db.models.fields.files import FieldFile +from django.db.models.signals import pre_delete + +def get_doc_dir(instance, filename): + from pytils import translit + return u'import_xls/import/%s' %translit.translify(filename) + + +def file_cleanup(sender, instance, *args, **kwargs): + ''' + Deletes the file(s) associated with a model instance. The model + is not saved after deletion of the file(s) since this is meant + to be used with the pre_delete signal. + ''' + for field_name, _ in instance.__dict__.iteritems(): + field = getattr(instance, field_name) + if issubclass(field.__class__, FieldFile) and field.name: + field.delete(save=False) + +class LogManager(models.Manager): + def create_log(self, work_file, errors): + """ + + :param work_file: executing file + :param errors: list of errors ([{'event name':['err1', 'err2']}]) + :return: object log + """ + LOG_DIRECTORY = settings.MEDIA_ROOT+'import_xls/logs/' + name= '111.txt' + filename = LOG_DIRECTORY + name + + log_file = open(filename, "w") + for error in errors: + event_name = ';'.join(error.keys()) + errs = '' + for err in error.values(): + errs += '; '.join(err) + errs += ';' + + log_file.write('%s: %s\n'%(event_name, errs)) + + log_file.close() + #update.log_file.name = 'updates/'+name + log = Log(work_file=work_file) + log.log.name = 'import_xls/logs/' + name + #log = Log.objects.create(work_file=work_file, log=log_file) + log.save() + return log + + def create_log_name(self, work_file): + log = Log.objects.create(work_file=work_file) + LOG_DIRECTORY = settings.MEDIA_ROOT+'import_xls/logs/' + name= 'log_%d.log'%log.id + filename = LOG_DIRECTORY + name + log_file = open(filename, "w").close() + log.log.name = 'import_xls/logs/' + name + log.save() + return log + + +class Log(models.Model): + work_file = models.FileField(upload_to=get_doc_dir) + log = models.FileField(upload_to='import_xls/logs/', blank=True) + type = models.CharField(max_length=10, default='IMPORT') + created = models.DateTimeField(auto_now_add=True) + + objects = models.Manager() + custom = LogManager() + + class Meta: + ordering = ['-created'] + +pre_delete.connect(file_cleanup, sender=Log) + diff --git a/import_xls/utils.py b/import_xls/utils.py index de52aac3..31b8d222 100644 --- a/import_xls/utils.py +++ b/import_xls/utils.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- import urllib2 import time, xlrd +import os +from PIL import Image from django.conf import settings from django.utils import translation from hvad.utils import get_translation_aware_manager @@ -30,6 +32,7 @@ def to_date(value): return None if isinstance(value, unicode) or isinstance(value, str): + try: t = time.strptime(value, "%d.%m.%Y") except ValueError: @@ -88,9 +91,13 @@ def to_theme(obj, value): theme_ids = value.split(',') if theme_ids == ['']: - return + return u'Неправильное значение' obj.theme.clear() obj.theme.add(*Theme.objects.filter(id__in=theme_ids)) + if not Theme.objects.filter(id__in=theme_ids).exists(): + return u'Нет совпадений' + return None + def to_tag(obj,value): if value == [""]: @@ -100,8 +107,7 @@ def to_tag(obj,value): if names: obj.tag.clear() obj.tag.add(*Tag.objects.filter(translations__name__in=names, theme__in=obj.theme.all())) - else: - return + return None @@ -130,6 +136,7 @@ def to_periodic(value): def to_audience(value, model=Exposition): if value: + translation.activate('ru') l = value.split(', ') if l: new_list = [] @@ -165,7 +172,7 @@ def save_logo(obj, path): try: alt_name = get_alternative_filename(full_path, file_name) except UnicodeEncodeError: - return None + return u'Некоректное название файла' download_to = full_path+alt_name @@ -181,9 +188,9 @@ def save_logo(obj, path): return None try: - response = urllib2.urlopen(url, timeout=15) + response = urllib2.urlopen(url, timeout=5) except: - return None + return u'Превышено время ожидания' with open(download_to,'wb') as f: try: @@ -191,14 +198,20 @@ def save_logo(obj, path): f.close() except: # can be timeout - return None + return u'Превышено время ожидания' + try: + # check if image + im=Image.open(download_to) + except IOError: + os.remove(download_to) + return u'Неправильный формат логотипа' obj.logo = logo_path + alt_name try: obj.save() except: print('logo exception. logo: %s'%obj.logo) - return None + return u'Неизвестная ошибка' @@ -207,10 +220,10 @@ def check_quality_label(obj, value, label): try: value = int(value) except: - return bit + return None if value: setattr(bit, label, True) - return bit + return None def to_user(value): try: diff --git a/proj/admin_urls.py b/proj/admin_urls.py index 85b34d32..47bbfeaf 100644 --- a/proj/admin_urls.py +++ b/proj/admin_urls.py @@ -19,6 +19,7 @@ urlpatterns = required( url(r'^company/', include('company.admin_urls')), url(r'^conference/', include('conference.admin_urls')), url(r'^country/', include('country.admin_urls')), + url(r'^expobanners/', include('expobanner.admin_urls')), url(r'^exposition/', include('exposition.admin_urls')), url(r'^news/', include('news.admin_urls')), url(r'^organiser/', include('organiser.admin_urls')), @@ -32,6 +33,8 @@ urlpatterns = required( url(r'^webinar/', include('webinar.admin_urls')), url(r'^settings/', include('settings.admin_urls')), url(r'^meta/', include('meta.admin_urls')), + url(r'^import_xls/', include('import_xls.admin_urls')), + url(r'^language/add/', 'directories.admin.language_add'), url(r'^currency/add/', 'directories.admin.currency_add'), # ajax requests diff --git a/proj/settings.py b/proj/settings.py index 7c5b0dd3..911fe09d 100644 --- a/proj/settings.py +++ b/proj/settings.py @@ -319,8 +319,10 @@ INSTALLED_APPS = ( 'core', 'country', 'directories', + 'expobanner', 'exposition', 'file', + 'import_xls', 'news', 'note', 'organiser', diff --git a/proj/urls.py b/proj/urls.py index b8aa4627..a8906dc1 100644 --- a/proj/urls.py +++ b/proj/urls.py @@ -11,6 +11,9 @@ class Robot(TemplateView): template_name = 'robots.txt' content_type = 'text/plain' +class YandexCheck(TemplateView): + template_name = 'client/simple_pages/yandex_check.html' + from sitemaps import ExpoCard, ExpoCity, ExpoCountry, ExpoTheme, ExpoTag, ConfCard, ConfCity, ConfCountry, ConfTheme,\ ConfTag, NewsSiteMap, BlogsSiteMap, Additional, Important @@ -26,8 +29,6 @@ sitemaps = { handler404 = 'proj.views.error404' urlpatterns = patterns('', - url(r'^wizard/', include('wizard.urls')), - url(r'^acquire_email/$', 'registration.backends.default.views.acquire_email', name = 'acquire_email'), url(r'^rss/', include('core.urls')), #url(r'^__debug__/', include(debug_toolbar.urls)), url(r'^sitemap-(?P
.+)\.xml$', views.sitemap, {'sitemaps': sitemaps}), @@ -36,10 +37,13 @@ urlpatterns = patterns('', url(r'^sitemap\.xml$', views.index, {'sitemaps': sitemaps}), url(r'^sitemap-(?P
.+)\.xml$', views.sitemap, {'sitemaps': sitemaps}), url(r'^robots.txt$', Robot.as_view()), + url(r'^yandex_4c326c16c916403e.html$', YandexCheck.as_view()), url(r'^$', MainPageView.as_view()), url(r'^page/', include('core.simple_urls')), url(r'^theme/', include('theme.urls')), url(r'^places/', include('place_exposition.urls')), + url(r'^translators/', include('translator.urls')), + url(r'^expo-b/', include('expobanner.urls')), url(r'^', include('accounts.urls')), url(r'^', include('exposition.urls')), url(r'^', include('settings.conference_old_urls')), # conference redirects from old version @@ -76,6 +80,7 @@ urlpatterns = patterns('', # ajax urls urlpatterns += patterns('', + url(r'^ajax/get_popover/$', 'settings.views.get_popover_info'), url(r'^registration/reply/$', 'registration.backends.default.views.RegisterReply'), url(r'^register/', 'registration.backends.default.views.RegisterAjaxView'), url(r'^register-complete/', 'registration.backends.default.views.complete_registration'), diff --git a/proj/views.py b/proj/views.py index 47124c8e..0db0e5bd 100644 --- a/proj/views.py +++ b/proj/views.py @@ -66,7 +66,9 @@ def error404(request): expo_themes = Theme.active.expo_themes_with_count() conf_themes = Theme.active.conference_themes_with_count() context.update({'expo_themes': expo_themes, 'conf_themes': conf_themes}) - return render_to_response('client/404.html', context, context_instance=RequestContext(request)) + response = render_to_response('client/404.html', context, context_instance=RequestContext(request)) + response.status_code = 404 + return response class MainPageView(JitterCacheMixin, TemplateView): @@ -76,7 +78,7 @@ class MainPageView(JitterCacheMixin, TemplateView): def get_context_data(self, **kwargs): context = super(MainPageView, self).get_context_data(**kwargs) - events = Exposition.objects.language().select_related('country', 'city', 'place').filter(main_page=1) + events = Exposition.objects.language().select_related('country', 'city', 'place').filter(main_page__gte=1).order_by('-main_page') exposition_themes = Theme.objects.language().order_by('-main_page').filter(types=Theme.types.exposition)[:6] conference_themes = Theme.objects.language().order_by('-main_page').filter(types=Theme.types.conference)[:6] diff --git a/service/admin.py b/service/admin.py index 584ec09e..91ae029d 100644 --- a/service/admin.py +++ b/service/admin.py @@ -4,6 +4,7 @@ from django.http import HttpResponseRedirect, HttpResponse from django.core.context_processors import csrf from django.conf import settings from django.contrib.auth.decorators import login_required +from django.views.generic import ListView, FormView #models and forms from models import Service from forms import ServiceForm, ServiceDeleteForm @@ -114,3 +115,30 @@ def get_city(request): return render_to_response('checkbox_option.html', {'options': cities}) else: return HttpResponse('error') + + +class ServiceControlList(ListView): + model = Service + template_name = 'admin/service/control_list.html' + paginate_by = 20 + +from django.views.generic.detail import SingleObjectMixin +from django.views.generic.edit import FormMixin +from django.views.generic import DetailView +from service.forms import ServiceControlForm +class ServiceControl(FormMixin, DetailView): + form_class = ServiceControlForm + template_name = 'admin/service/control.html' + model = Service + + + def get_form(self, form_class): + obj = self.object + data = obj.get_current_state() + + return form_class(data) + + def get_context_data(self, **kwargs): + context = super(ServiceControl, self).get_context_data(**kwargs) + context['form'] = self.get_form(self.form_class) + return context \ No newline at end of file diff --git a/service/admin_urls.py b/service/admin_urls.py index 682785fc..4dda045f 100644 --- a/service/admin_urls.py +++ b/service/admin_urls.py @@ -2,8 +2,11 @@ from django.conf.urls import patterns, include, url from views import CallBackListView, VisitListView, TranslationListView, AdvertisingListView, \ ParticipationListView, RemoteListView,TicketsListView +from service.admin import ServiceControlList, ServiceControl urlpatterns = patterns('service.admin', + url(r'^control/list/$', ServiceControlList.as_view()), + url(r'^control/(?P.*)/$', ServiceControl.as_view()), url(r'^add.*/$', 'service_add'), url(r'^delete/(?P.*)/$', 'service_delete'), url(r'^change/(?P.*)/$', 'service_change'), @@ -17,6 +20,6 @@ urlpatterns = patterns('service.admin', url(r'order/tickets/$', TicketsListView.as_view()), #ajax url(r'^get_city/$', 'get_city'), - #url(r'^get_country/$', 'get_country'), +#url(r'^get_country/$', 'get_country'), ) diff --git a/service/forms.py b/service/forms.py index 1431a76e..946b0d64 100644 --- a/service/forms.py +++ b/service/forms.py @@ -121,4 +121,29 @@ class ServiceDeleteForm(forms.ModelForm): class Meta: model = Service - fields = ('url',) \ No newline at end of file + fields = ('url',) + + +from country.models import Area, Country +from exposition.models import Exposition +from conference.models import Conference + +class ServiceControlForm(forms.Form): + event = [{'verbose': 'Выставки', 'model': Exposition, 'id': 1, 'service_bit': 'expo'}, + {'verbose': 'Конференции', 'model': Conference, 'id': 2, 'service_bit': 'conference'}] + region = forms.ChoiceField(required=False, label='Регион', + choices=[('', '')]+[(item.id, item.name) + for item in list(Area.objects.all())]) + country = forms.MultipleChoiceField(required=False, label='Страны', + choices=[('', '')]+[(item.id, item.name) + for item in list(Country.objects.all())]) + country_all = forms.BooleanField(required=False) + expositions = forms.CharField(label=u'Выставки', widget=forms.HiddenInput(), required=False) + conferences = forms.CharField(label=u'Конференции', widget=forms.HiddenInput(), required=False) + + def __init__(self, *args, **kwargs): + super(ServiceControlForm, self).__init__(*args, **kwargs) + self.fields['event_type'] = forms.MultipleChoiceField(required=False, label = 'Тип события', + widget=forms.CheckboxSelectMultiple(), + choices=[(item['service_bit'], item['verbose']) + for item in self.event]) \ No newline at end of file diff --git a/service/models.py b/service/models.py index e490e574..d0d711f3 100644 --- a/service/models.py +++ b/service/models.py @@ -47,9 +47,60 @@ class Service(TranslatableModel): def get_price(self): pr = self.price - - - + def get_current_state(self): + """ + uses for control form + :return: + """ + from country.models import Country + country_all = False + country = [] + region = [] + expositions = [] + conferences = [] + service = self.url + event_type = [key for key, value in self.type.iteritems() if value] + if not event_type: + return {'event_type': event_type, + 'region': region, + 'country': country, + 'country_all': country_all, + 'expositions': expositions, + 'conferences': conferences} + + count1 = Country.objects.filter().count() + count2 = Country.objects.filter(services=getattr(Country.services, service)).count() + country_all = count1 == count2 + if not country_all: + from exposition.models import Exposition + from conference.models import Conference + from country.models import Area + from django.utils.translation import get_language + lang = get_language() + + countries = list(Country.objects.language(lang).filter(services=getattr(Country.services, service))) + + expositions = [(item.id, item.name) for item in Exposition.enable.upcoming().exclude(country__in=countries, services=getattr(Exposition.services, service))] + conferences = [(item.id, item.name) for item in Conference.enable.upcoming().exclude(country__in=countries, services=getattr(Conference.services, service))] + + region = [] + countries = set(countries) + for item in list(Area.objects.language(lang).all()): + print(item) + area_countries = item.countries() + if set(area_countries).issubset(countries): + region.append((item.id, item.name)) + countries = countries - set(area_countries) + + country = [(item.id, item.name) for item in list(countries)] + + state = {'event_type': event_type, + 'region': region, + 'country': country, + 'country_all': country_all, + 'expositions': expositions, + 'conferences': conferences} + return state from django.db.models.signals import post_save from functions.signal_handlers import post_save_handler @@ -105,6 +156,7 @@ class Translation(AbstractOrder): languages = models.TextField(blank=True) themes = models.TextField(blank=True) + class Visit(AbstractOrder): fr = models.DateField() to = models.DateField() diff --git a/settings/management/commands/do_inflect.py b/settings/management/commands/do_inflect.py index 601a69a3..c226f08a 100644 --- a/settings/management/commands/do_inflect.py +++ b/settings/management/commands/do_inflect.py @@ -8,7 +8,7 @@ from city.models import City CITIES = settings.MEDIA_ROOT+'/import/cities_inflect.xls' TAGS = settings.MEDIA_ROOT+'/import/tags_inflect.xls' - +import inspect, os class Command(BaseCommand): def handle(self, *args, **options): diff --git a/settings/templatetags/template_filters.py b/settings/templatetags/template_filters.py index 10c11444..fb26e631 100644 --- a/settings/templatetags/template_filters.py +++ b/settings/templatetags/template_filters.py @@ -156,6 +156,18 @@ def timetable_by_day(qs, day): def random_social(value): return bool(random.getrandbits(1)) +@register.filter +def random3(value): + return random.randrange(0,3) + +@register.filter +def random4(value): + return random.randrange(0,4) + +@register.filter +def random5(value): + return random.randrange(0,5) + @register.filter def fourth(value): # return almost in 75% cases True in 25% False @@ -224,7 +236,10 @@ def without_page(value): @register.filter def note_by_user(obj, user): - return obj.get_note_by_user(user.id) + if obj: + + return obj.get_note_by_user(user.id) + return '' @register.filter def isdigit(value): @@ -282,4 +297,13 @@ def generate_countries_list(value): - return ul1+ul2+ul3 \ No newline at end of file + return ul1+ul2+ul3 + +@register.filter +def how_many_years(value): + if not isinstance(value, datetime.date): + return '' + now = datetime.date.today() + delta = now - value + + return delta.days/365 diff --git a/settings/views.py b/settings/views.py index 6404d699..0655f9c3 100644 --- a/settings/views.py +++ b/settings/views.py @@ -10,7 +10,7 @@ from theme.models import Tag, Theme from place_exposition.models import PlaceExposition from place_conference.models import PlaceConference from company.models import Company -import datetime +from conference.models import Conference # every this model must have method get_subcategories categories = {'area':{'sub':True, 'model':Area, 'sub_categorie_name':'co'}, @@ -44,19 +44,22 @@ def search_autocomplete(request): term = request.GET['term'] form = request.GET['form'] if form == 'place': - areas = [{'text':item.name, 'id':item.id, 'name':'area'} for item in Area.objects.filter(translations__name__contains=term)] - countries = [{'text':item.name, 'id':item.id, 'name':'co'} for item in Country.objects.select_related('exposition_country')\ - .filter(exposition_country__country__isnull=False, translations__language_code=lang, translations__name__contains=term).distinct()] - cities = [{'text':item.name, 'id':item.id, 'name':'ci'} for item in City.objects.select_related('exposition_city')\ - .filter(exposition_city__city__isnull=False, translations__language_code=lang, translations__name__contains=term).distinct()] - - objects = areas + countries + cities - return HttpResponse(json.dumps(objects), content_type='application/json') + qs = list(SearchQuerySet().models(Country, City, Area).autocomplete(content_auto=term)[:6]) + objects = [{'text':get_by_lang(item, 'name', lang), 'id': item.pk, 'name': item.form_name} for item in qs] + #areas = [{'text':item.name, 'id':item.id, 'name':'area'} for item in Area.objects.filter(translations__name__contains=term)] + + #countries = [{'text':item.name, 'id':item.id, 'name':'co'} for item in Country.objects.select_related('exposition_country')\ + # .filter(exposition_country__country__isnull=False, translations__language_code=lang, translations__name__contains=term).distinct()] + #cities = [{'text':item.name, 'id':item.id, 'name':'ci'} for item in City.objects.select_related('exposition_city')\ + # .filter(exposition_city__city__isnull=False, translations__language_code=lang, translations__name__contains=term).distinct()] + + #objects = areas + countries + cities + return HttpResponse(json.dumps(objects, indent=4), content_type='application/json') if form == 'subj': objects = [{'text': get_by_lang(item, 'name', lang), 'id':item.pk, 'name': item.form_name, 'cat': get_by_lang(item, 'parent', lang)} for item in SearchQuerySet().models(Theme, Tag).autocomplete(content_auto=term)] - return HttpResponse(json.dumps(objects), content_type='application/json') + return HttpResponse(json.dumps(objects, indent=4), content_type='application/json') else: - return HttpResponse("Doesn't implemented yet") + return HttpResponse("Don't implemented yet") else: @@ -87,29 +90,28 @@ def get_by_lang(item, field, lang='en'): :return: """ return getattr(item, field+'_'+lang) - - - - +import datetime def expo_autosearch(request): if request.GET: lang = translation.get_language() term = request.GET['term'] + term = term.strip() d = datetime.date.today() expos = list(SearchQuerySet().models(Exposition).filter(data_end__gte=d).autocomplete(content_auto=term).order_by('data_begin','text')[:6]) - themes = list(SearchQuerySet().models(Tag).autocomplete(content_auto=term).order_by('text')[:15]) - res = expos + themes + confs = list(SearchQuerySet().models(Conference).filter(data_end__gte=d).autocomplete(content_auto=term).order_by('data_begin','text')[:6]) + tags = list(SearchQuerySet().models(Tag).autocomplete(content_auto=term).order_by('text')[:6]) + themes = list(SearchQuerySet().models(Theme).autocomplete(content_auto=term).order_by('text')[:6]) + res = expos + themes + tags + confs result = [{'cat': get_by_lang(item, 'catalog_name', lang), 'text': '%s (%s)'%(get_by_lang(item, 'name', lang),get_by_lang(item, 'parent', lang)) if get_by_lang(item, 'parent', lang) else get_by_lang(item, 'name', lang), 'url':item.url, 'id':item.pk, 'name': item.form_name} for item in res] result = sorted(result, key=lambda x:x['cat'], reverse=True) - return HttpResponse(json.dumps(result), content_type='application/json') + return HttpResponse(json.dumps(result, indent=4), content_type='application/json') else: raise Http404 - def place_autosearch(request): if request.GET: lang = translation.get_language() @@ -129,4 +131,52 @@ def company_autosearch(request): result = sorted(result, key=lambda x:x['cat']) return HttpResponse(json.dumps(result), content_type='application/json') else: - raise Http404 \ No newline at end of file + raise Http404 + +#------------------------------------------------------ +# POPOVERS +#------------------------------------------------------ +import random +from django.shortcuts import render +from django.template.loader import render_to_string +def get_popover(request): + response = {'success': True} + theme_id = request.GET.get('theme_id') + themes = {'2': ['client/popups/auto_modal.html', 'client/popups/auto_banner.html'], + '32': ['client/popups/auto_modal.html', 'client/popups/auto_banner.html', 'client/popups/cemat_modal.html', 'client/popups/cemat_banner1.html', 'client/popups/cemat_banner2.html'], + '54': ['client/popups/cemat_modal.html', 'client/popups/cemat_banner1.html', 'client/popups/cemat_banner2.html'], + '26': ['client/popups/cemat_modal.html', 'client/popups/cemat_banner1.html', 'client/popups/cemat_banner2.html'], + '22': ['client/popups/cemat_modal.html', 'client/popups/cemat_banner1.html', 'client/popups/cemat_banner2.html'], + '15': ['client/popups/cemat_modal.html', 'client/popups/cemat_banner1.html', 'client/popups/cemat_banner2.html'], + '44': ['client/popups/cemat_modal.html', 'client/popups/cemat_banner1.html', 'client/popups/cemat_banner2.html'], + '30': ['client/popups/cemat_modal.html', 'client/popups/cemat_banner1.html', 'client/popups/cemat_banner2.html']} + popovers = themes.get(theme_id) + if not popovers: + popovers = ['fail'] + response['success'] = False + + popover = random.choice(popovers) + html = render_to_string(popover) + + response['html'] = html + return HttpResponse(json.dumps(response), content_type='application/json') + +from banners.models import Redirect +from django.db.models import F +import datetime + +def set_cookie(response, key, value, days_expire = 7): + if days_expire is None: + max_age = 365 * 24 * 60 * 60 #one year + else: + max_age = days_expire * 24 * 60 * 60 + expires = datetime.datetime.strftime(datetime.datetime.utcnow() + datetime.timedelta(seconds=max_age), "%a, %d-%b-%Y %H:%M:%S GMT") + response.set_cookie(key, value, max_age=max_age, expires=expires) + +def get_popover_info(request): + id = request.GET.get('rdr') + if id: + Redirect.objects.filter(id=id).update(views = F('views') + 1) + response = HttpResponse('success') + set_cookie(response, 'popover_test1', '1') + return response \ No newline at end of file diff --git a/static/custom_js/find_events.js b/static/custom_js/find_events.js new file mode 100644 index 00000000..a92cb126 --- /dev/null +++ b/static/custom_js/find_events.js @@ -0,0 +1,47 @@ +function make_event_select(id, url, placeholder){ + $(id).select2({ + placeholder: placeholder, + multiple: true, + ajax: { + + url: url, + width: '550px', + dataType: "json", + quietMillis: 200, + multiple: true, + + data: function(term, page, theme){ + return {term: term, + page: page}; + }, + + results: function (data) { + var results = []; + $.each(data, function(index, item){ + results.push({ + id: item.id, + text: item.label + }); + }); + return {results: results}; + } + }, + initSelection : function(element, callback) { + var data = []; + $(element.val().split(",")).each(function(i) { + var item = this.split(':'); + data.push({ + id: item[0], + text: item[1] + }); + }); + callback(data); + } + }); +} + + +$(document).ready(function(){ + make_event_select('#id_expositions', '/admin/exposition/search/', 'Выставки'); + make_event_select('#id_conferences', '/admin/conference/search/', 'Конференции'); +}); diff --git a/static/custom_js/main.js b/static/custom_js/main.js index 3c301189..7f2f0d3b 100644 --- a/static/custom_js/main.js +++ b/static/custom_js/main.js @@ -112,7 +112,13 @@ function postStat(data, textStatus){ $(document).ready(function(){ - +/* + $('#id_created').datetimepicker({ + todayHighlight: true, + format : 'yyyy-mm-dd', + minView:2 + }); +*/ $('#photo_form').on('submit', function(e){ e.preventDefault(); var url = $(this).attr('action'); @@ -230,11 +236,7 @@ $(document).ready(function(){ }); // end on-of events - $('select').select2({ - width: 'element', - allowClear: true - });//end select @@ -485,5 +487,11 @@ $(document).ready(function(){ }); }); + $('select').select2({ + width: 'element', + allowClear: true + + });//end select + }); diff --git a/static/img/expob/cemat15.gif b/static/img/expob/cemat15.gif new file mode 100644 index 00000000..9493a63b Binary files /dev/null and b/static/img/expob/cemat15.gif differ diff --git a/static/img/expob/cemat15_v2.gif b/static/img/expob/cemat15_v2.gif new file mode 100644 index 00000000..6434be8f Binary files /dev/null and b/static/img/expob/cemat15_v2.gif differ diff --git a/static/img/expob/mims15.gif b/static/img/expob/mims15.gif new file mode 100644 index 00000000..7557051e Binary files /dev/null and b/static/img/expob/mims15.gif differ diff --git a/templates/admin/base.html b/templates/admin/base.html index 9861275b..55d78941 100644 --- a/templates/admin/base.html +++ b/templates/admin/base.html @@ -31,6 +31,10 @@ {# The fav icon #} + {# datetimepicker #} + + + {% block scripts %} {% endblock %} @@ -72,7 +76,7 @@ - + {% block bot_scripts %} {% endblock %} \ No newline at end of file diff --git a/templates/admin/city/city_add.html b/templates/admin/city/city_add.html index ff7aaec1..da12c2cc 100644 --- a/templates/admin/city/city_add.html +++ b/templates/admin/city/city_add.html @@ -17,7 +17,7 @@ {% block body %} {# Uses multilang.html template for translated fields #} -
{% csrf_token %} + {% csrf_token %}
{% if obj_id %} Изменить {% else %} Добавить {% endif %}город @@ -47,6 +47,13 @@
{{ form.country}}
+ +
+ +
{{ form.logo }} + {{ form.logo.errors }} +
+
{# region #} {% with field='region' form=form languages=languages %} {% include 'admin/forms/multilang.html' %} diff --git a/templates/admin/conference/conference.html b/templates/admin/conference/conference.html index 0201f346..51811f7f 100644 --- a/templates/admin/conference/conference.html +++ b/templates/admin/conference/conference.html @@ -181,6 +181,14 @@ {{ form.web_page.errors }} + {# organiser #} +
+ +
{{ form.org }} + {{ form.org.errors }} +
+
+ {# link #}
diff --git a/templates/admin/conference/conference_list.html b/templates/admin/conference/conference_list.html index 327f4a31..7d6fe645 100644 --- a/templates/admin/conference/conference_list.html +++ b/templates/admin/conference/conference_list.html @@ -1,12 +1,19 @@ {% extends 'admin_list.html' %} {% load static %} -{% block scripts %} - + +{% block styles %} + +td a{ + float:left; + margin: 0 10px 10px 0 +} + {% endblock %} + {% block body %}
@@ -30,11 +37,16 @@
+ + + + + @@ -42,30 +54,28 @@ - - - + + - - - @@ -77,4 +87,33 @@ {# pagination #} {% include 'admin/includes/admin_pagination.html' with page_obj=object_list %} + + + {% endblock %} \ No newline at end of file diff --git a/templates/admin/country/country_add.html b/templates/admin/country/country_add.html index 0e48444a..6b06e613 100644 --- a/templates/admin/country/country_add.html +++ b/templates/admin/country/country_add.html @@ -41,6 +41,13 @@ {% with field='description' form=form languages=languages %} {% include 'admin/forms/multilang.html' %} {% endwith %} + +
+ +
{{ form.logo }} + {{ form.logo.errors }} +
+
{# capital #}
diff --git a/templates/admin/expobanner/banners_control.html b/templates/admin/expobanner/banners_control.html new file mode 100644 index 00000000..e307cecd --- /dev/null +++ b/templates/admin/expobanner/banners_control.html @@ -0,0 +1,33 @@ +{% extends 'base.html' %} + + +{% block body %} +
+
+
+

Создание

+
+ +
+ +
+
+

Список

+ +
+ +
+
+{% endblock %} \ No newline at end of file diff --git a/templates/admin/expobanner/default_form.html b/templates/admin/expobanner/default_form.html new file mode 100644 index 00000000..30c72263 --- /dev/null +++ b/templates/admin/expobanner/default_form.html @@ -0,0 +1,59 @@ +{% extends 'base.html' %} +{% load static %} + +{% block scripts %} + + + +{% endblock %} + +{% block body %} + {% csrf_token %} +
+ +
+
+

{{ form.verbose }}

+
+
+ {% for field in form %} +
+ +
{{ field }} + {{ field.errors }} +
+
+ {% endfor %} +
+
+
+ +
+ + +
+ +{% endblock %} \ No newline at end of file diff --git a/templates/admin/expobanner/default_list.html b/templates/admin/expobanner/default_list.html new file mode 100644 index 00000000..5b8696c6 --- /dev/null +++ b/templates/admin/expobanner/default_list.html @@ -0,0 +1,34 @@ +{% extends 'base.html' %} + +{% block body %} + +
+
+

{{ verbose }}

+
+
+ {% block list_table %} +
Название Дата начала   
{{ item.name }}{{ item.data_begin }} + {{ item.data_begin|date:"Y-m-d" }}Копировать Отключить - + Включить + + + Изменить + + + на сайте - - - Изменить + + Удалить - - Удалить - -
+ + + + + + + + + {% for item in object_list %} + + + + + {% endfor %} + +
Объект 
{{ item }}Изменить
+ {% endblock %} +
+ {# pagination #} + {% include 'admin/includes/admin_pagination.html' with page_obj=object_list %} +
+ +{% endblock %} \ No newline at end of file diff --git a/templates/admin/exposition/exposition.html b/templates/admin/exposition/exposition.html index 4ef1496b..3b2be57b 100644 --- a/templates/admin/exposition/exposition.html +++ b/templates/admin/exposition/exposition.html @@ -22,26 +22,10 @@ {# selects #} - {# datepicker #} - - - - - - - - {# datetimepicker #} - - + +{% endblock %} diff --git a/templates/admin/import templates/log.html b/templates/admin/import templates/log.html new file mode 100644 index 00000000..80256163 --- /dev/null +++ b/templates/admin/import templates/log.html @@ -0,0 +1,46 @@ +{% extends 'base.html' %} +{% load static %} + + +{% block body %} +{% comment %} +Displays lists of all cities in the table + and creating buttons which can change each city +{% endcomment %} + +
+
+

Логи импорта

+
+
+ + + + + + + + + + + + {% for item in object_list %} + + + + + + + {% endfor %} + +
Время импортаРобочий файлЛог 
{{ item.created|date:"Y-m-d H:m:s" }}скачатьскачать + + Удалить + +
+
+ + {% include 'admin/includes/admin_pagination.html' with page_obj=objects %} + +
+{% endblock %} \ No newline at end of file diff --git a/templates/admin/import templates/log_delete.html b/templates/admin/import templates/log_delete.html new file mode 100644 index 00000000..fbeb3a2f --- /dev/null +++ b/templates/admin/import templates/log_delete.html @@ -0,0 +1,15 @@ +{% extends 'base.html' %} + +{% block body %} + +
{% csrf_token %} + +
+

Вы действительно хотите удалить {{ object }}?

+
+ + Нет +
+ + +{% endblock %} \ No newline at end of file diff --git a/templates/admin/includes/admin_nav.html b/templates/admin/includes/admin_nav.html index 51a37be8..9f33389b 100644 --- a/templates/admin/includes/admin_nav.html +++ b/templates/admin/includes/admin_nav.html @@ -12,6 +12,7 @@
  • Импорт
  • Экспорт
  • +
  • Архив логов
  • @@ -104,6 +105,13 @@ + +
    diff --git a/templates/admin/service/control.html b/templates/admin/service/control.html new file mode 100644 index 00000000..99ed06b5 --- /dev/null +++ b/templates/admin/service/control.html @@ -0,0 +1,78 @@ +{% extends 'base.html' %} +{% load static %} + +{% block scripts %} + + +{# selects #} + + + +{% endblock %} + +{% block body %} + +
    {% csrf_token %} +
    + Управление услугой {{ object.name }} + +
    +
    +

    +
    +
    + {# event_type #} +
    + +
    + {{ form.event_type }} +
    +
    + + {# country_all #} +
    + +
    {{ form.country_all }} + {{ form.country_all.errors }} +
    +
    + + {# region #} +
    + +
    {{ form.region }} + {{ form.region.errors }} +
    +
    + + {# country #} +
    + +
    {{ form.country }} + {{ form.country.errors }} +
    +
    + {# expositions #} +
    + +
    {{ form.expositions }} + {{ form.expositions.errors }} +
    +
    + {# conferences #} +
    + +
    {{ form.conferences }} + {{ form.conferences.errors }} +
    +
    + +
    +
    +
    +
    +{% endblock %} + +{% block bot_scripts %} + +{% endblock %} \ No newline at end of file diff --git a/templates/admin/service/control_list.html b/templates/admin/service/control_list.html new file mode 100644 index 00000000..38bf41b8 --- /dev/null +++ b/templates/admin/service/control_list.html @@ -0,0 +1,39 @@ +{% extends 'admin_list.html' %} + +{% block body %} +
    +
    +

    Список услуг

    +
    +
    + + + + + + + + + + + {% for item in object_list %} + + + + + + + + + {% endfor %} + +
    idНазвание 
    {{ item.id }}{{ item.name }} + + Управлять + +
    +
    + {# pagination #} + {% include 'admin/includes/admin_pagination.html' with page_obj=object_list %} +
    +{% endblock %} \ No newline at end of file diff --git a/templates/admin/settings/main_page.html b/templates/admin/settings/main_page.html index 5018c3f7..cd51e77f 100644 --- a/templates/admin/settings/main_page.html +++ b/templates/admin/settings/main_page.html @@ -89,48 +89,5 @@ {% endblock %} {% block bot_scripts %} - + {% endblock %} \ No newline at end of file diff --git a/templates/admin/translator/translator.html b/templates/admin/translator/translator.html new file mode 100644 index 00000000..261f67ad --- /dev/null +++ b/templates/admin/translator/translator.html @@ -0,0 +1,133 @@ +{% extends 'base.html' %} +{% load static %} +{# Displays translator form and file form in modal window #} + + +{% block scripts %} + + + {# selects #} + + + + {# ajax #} + + {# datetimepicker #} + + + + + +{% endblock %} + +{% block body %} +
    {% csrf_token %} +
    + Изменить переводчика(на сайте) + +
    +
    +

    Основная информация

    +
    +
    + {# name #} +
    + +
    {{ form_user.first_name }} + {{ form_user.first_name.errors }} +
    +
    + + {# surname #} +
    + +
    {{ form_user.last_name }} + {{ form_user.last_name.errors }} +
    +
    + + {# country #} +
    + +
    {{ form_profile.country }} + {{ form_profile.country.errors }} +
    +
    + + {# city #} +
    + +
    {{ form_profile.city }} + {{ form_profile.city.errors }} +
    +
    + + {# logo #} +
    + +
    {{ form_profile.avatar }} + {{ form_profile.avatar.errors }} +
    +
    + + +
    + +
    + +
    +
    +

    Информация по переводчику

    +
    +
    + + {# car #} +
    + +
    {{ form.car }} + {{ form.car.errors }} +
    +
    + + {# birth #} +
    + +
    {{ form.birth }} + {{ form.birth.errors }} +
    +
    + + {# gender #} +
    + +
    {{ form.gender }} + {{ form.gender.errors }} +
    +
    + {# time #} + + {% include 'admin/forms/multilang.html' with field='education' form=form languages=languages%} + {% include 'admin/forms/multilang.html' with field='specialization' form=form languages=languages%} + {% include 'admin/forms/multilang.html' with field='languages' form=form languages=languages%} + {% include 'admin/forms/multilang.html' with field='native_language' form=form languages=languages%} + {% include 'admin/forms/multilang.html' with field='prices' form=form languages=languages%} + {% include 'admin/forms/multilang.html' with field='discounts' form=form languages=languages%} + + +
    +
    +
    + + +
    +
    +
    +{% endblock %} \ No newline at end of file diff --git a/templates/admin/translator/translator_all.html b/templates/admin/translator/translator_all.html index 180e0289..7b6abfb5 100644 --- a/templates/admin/translator/translator_all.html +++ b/templates/admin/translator/translator_all.html @@ -21,10 +21,9 @@ {{ item.id }} - {% for u in item.user.all %} - {{ u }} - {{ u.country }} - {% endfor %} + {{ item.get_full_name }} + {{ item.profile.country.name }} + diff --git a/templates/admin/translator/translator_list.html b/templates/admin/translator/translator_list.html index d348c662..0751ed35 100644 --- a/templates/admin/translator/translator_list.html +++ b/templates/admin/translator/translator_list.html @@ -28,6 +28,7 @@ id Пользователь Страна +   @@ -35,10 +36,8 @@ {{ item.id }} - {% for u in item.user.all %} - {{ u.get_full_name }} - {{ u.profile.country.name }} - {% endfor %} + {{ item.get_full_name }} + {{ item.profile.country.name }} diff --git a/templates/client/accounts/translators/translator_city.html b/templates/client/accounts/translators/translator_city.html new file mode 100644 index 00000000..7084eacd --- /dev/null +++ b/templates/client/accounts/translators/translator_city.html @@ -0,0 +1,108 @@ +{% extends 'base_catalog.html' %} +{% load i18n %} + + +{% block bread_scrumbs %} + +{% endblock %} + +{% block page_title %} + +{% endblock %} + +{% block content_list %} +
    +
    + + +
    +
    +
    {{ object.name }}
    +
    + +
    +

    Компания Serve Businesses Worldwide предлагает Вам возможность заказать услуги русскоговорящих переводчиков со знанием английского языка практически непосредственно в Великобритании.

    +
    + +
    +
    + +
    + +
    +
    +

    Коротко о наших преимуществах:

    +
      +
    • Эффективная цена
    • +
    • Опыт и профессионализм специалистов
    • +
    • Знание разных менталитетов и психологических аспектов проведения переговоров с зарубежными бизнесменами
    • +
    • Ориентированность в мировых выставочных комплексах
    • +
    • Гарантии, отчетность по договору, прозрачные безналичные расчеты в России
    • +
    + +
    +
    + +
    + +
    +
    +
    +
    +
    от 80 € / день
    + +
    +
    +
    +
    +
    + +
    + + + + +
    +{% endblock %} + diff --git a/templates/client/accounts/translators/translator_country.html b/templates/client/accounts/translators/translator_country.html new file mode 100644 index 00000000..121e297b --- /dev/null +++ b/templates/client/accounts/translators/translator_country.html @@ -0,0 +1,137 @@ +{% extends 'base_catalog.html' %} +{% load i18n %} + + +{% block bread_scrumbs %} + +{% endblock %} + +{% block page_title %} + +{% endblock %} + +{% block content_list %} +
    +
    + + +
    +
    +
    Переводчики {{ object.inflect }}
    +
    + +
    +

    Компания Serve Businesses Worldwide предлагает Вам возможность заказать услуги русскоговорящих переводчиков со знанием английского языка практически непосредственно в Великобритании.

    +

    Ниже приведен список наиболее часто востребованных территориальных направлений для оказания услуг перевода в Великобритании. Приведенный перечень не является исчерпывающим, поэтому, если Вы не нашли нужный Вам город, обратитесь к нашим консультантам.

    +
    +
    + {% if object.latitude and object.longitude %} + + {% endif %} + +
    +
    + +
    + + {% if object.big_cities.exists %} + {% with cities=object.big_cities.all %} +
    +

    Крупные города:

    + + + + + + +
    + +  
    +
    + +
    + {% endwith %} + {% endif %} + +
    +
    +

    Коротко о наших преимуществах:

    +
      +
    • Эффективная цена
    • +
    • Опыт и профессионализм специалистов
    • +
    • Знание разных менталитетов и психологических аспектов проведения переговоров с зарубежными бизнесменами
    • +
    • Ориентированность в мировых выставочных комплексах
    • +
    • Гарантии, отчетность по договору, прозрачные безналичные расчеты в России
    • +
    + +
    +
    + +
    + +
    +
    +
    +
    +
    от 80 € / день
    + +
    +
    +
    +
    +
    + + +
    + + + +
    +{% endblock %} \ No newline at end of file diff --git a/templates/client/accounts/translators/translator_profile.html b/templates/client/accounts/translators/translator_profile.html new file mode 100644 index 00000000..0c714b5f --- /dev/null +++ b/templates/client/accounts/translators/translator_profile.html @@ -0,0 +1,59 @@ +{% extends 'base_catalog.html' %} +{% load static %} +{% load i18n %} +{% load thumbnail %} +{% load template_filters %} + + +{% block bread_scrumbs %} + +{% endblock %} + +{% block content_list %} +
    +
    +
    + {% if object.profile.avatar %} + {% thumbnail object.profile.avatar "100x100" format="PNG" as im %} + + {% endthumbnail %} + {% else %} + + {% endif %} +
    +
    +

    {{ object.get_full_name }}

    +

    {{ object.translator.languages }}

    + +

    {% ifequal object.translator.gender 'female' %}{% endifequal %}{{ object.translator.birth|how_many_years }} лет{% if object.translator.car %}Есть личный автомобиль

    {% endif %} +
    +
    + {% if object.profile.country %} +

    {{ object.profile.country.name }} + {% if object.profile.city %}, {{ object.profile.city.name }}{% endif %}

    + {% endif %} + {% if object.translator.native_language %} +

    {% trans 'Родной язык' %} — {{ object.translator.native_language }}

    + {% endif %} +
    +
    + +
    + {% if object.translator.education %} +

    {% trans 'Образование' %}:

    + {{ object.translator.education }} +
    + {% endif %} +
    +
    +{% endblock %} \ No newline at end of file diff --git a/templates/client/accounts/translators/translators_by.html b/templates/client/accounts/translators/translators_by.html new file mode 100644 index 00000000..e3586b48 --- /dev/null +++ b/templates/client/accounts/translators/translators_by.html @@ -0,0 +1,33 @@ +{% extends 'base_catalog.html' %} +{% load i18n %} +{% load template_filters %} + +{% block bread_scrumbs %} + +{% endblock %} + +{% block page_title %} + +{% endblock %} + +{% block content_list %} + {% with objects=object_list %} + {% for obj in objects %} + {% set cur_word = obj.name %} + {% if cur_word|slice:":1"|lower != prev_word|slice:":1"|lower and forloop.counter != 1 %} + + {% endif %} + {% if cur_word|slice:":1"|lower != prev_word|slice:":1"|lower %} +
      +
      {{ cur_word|slice:":1"|upper }}
      + {% endif %} +
    • + {{ obj.name }} ({{ obj.translators_count }}) +
    • + {% set prev_word = obj.name %} + {% endfor %} + {% endwith %} +{% endblock %} \ No newline at end of file diff --git a/templates/client/blank.html b/templates/client/blank.html index a4323fea..5c14ac22 100644 --- a/templates/client/blank.html +++ b/templates/client/blank.html @@ -1,6 +1,8 @@ {% load static %} {% load i18n %} +{% load template_filters %} {% get_current_language as LANGUAGE_CODE %} + {% comment %} This template include basic anf main styles and js files, block with header and footer, which same in all pages, @@ -20,6 +22,8 @@ This template include basic anf main styles and js files, {% include 'includes/meta.html' %} + + @@ -108,6 +112,20 @@ This template include basic anf main styles and js files, ga('create', 'UA-3151423-1', 'auto'); ga('send', 'pageview'); + + @@ -147,7 +165,7 @@ This template include basic anf main styles and js files, {% include 'client/includes/footer.html' %} {% endblock %} -
      +
      {% if not user.is_authenticated %} {% include 'client/popups/login.html' %} {% include 'client/popups/register.html' %} @@ -156,7 +174,92 @@ This template include basic anf main styles and js files, {% endif %} {% include 'client/popups/callback.html' %} + {% block popup_banner %} + {% if not request.COOKIES.popover_test1 %} + {% if theme_for_filter %} + + + {% if theme_for_filter.id == 2 %} + {% if False|random_social %} + {% include 'client/popups/auto_modal.html' %} + {% else %} + {% include 'client/popups/auto_banner.html' %} + {% endif %} + {% endif %} + {% if theme_for_filter.id == 54 or theme_for_filter.id == 26 or theme_for_filter.id == 22 or theme_for_filter.id == 15 or theme_for_filter.id == 44 or theme_for_filter.id == 30 %} + {% with r=False|random3 %} + {% if r == 1 %} + {% include 'client/popups/cemat_modal.html' %} + {% else %} + {% if r == 2 %} + {% include 'client/popups/cemat_banner1.html' %} + {% else %} + {% include 'client/popups/cemat_banner2.html' %} + {% endif %} + {% endif %} + {% endwith %} + {% endif %} + + {% if theme_for_filter.id == 32 %} + {% with r=False|random5 %} + {% if r == 1 %} + {% include 'client/popups/auto_modal.html' %} + {% endif %} + + {% if r == 2 %} + {% include 'client/popups/auto_banner.html' %} + {% endif %} + {% if r == 3 %} + {% include 'client/popups/cemat_modal.html' %} + {% endif %} + {% if r == 4 %} + {% include 'client/popups/cemat_banner1.html' %} + {% endif %} + {% if r == 0 %} + {% include 'client/popups/cemat_banner2.html' %} + {% endif %} + {% endwith %} + {% endif %} + + + + + {% endif %} + {% endif %} + {% endblock %} {# if user doesnt have url- show form #} {% if 'partial_pipeline' not in request.session %} {% include 'client/popups/acquire_email.html' %} diff --git a/templates/client/exposition/exposition_detail.html b/templates/client/exposition/exposition_detail.html index aa55fdaf..8a365de1 100644 --- a/templates/client/exposition/exposition_detail.html +++ b/templates/client/exposition/exposition_detail.html @@ -1,5 +1,6 @@ {% extends 'base_catalog.html' %} {% load i18n %} +{% load template_filters %} {% block bread_scrumbs %}
      + {% else %} +
      +
      +
      + {{ event.country.name }}, {{ event.city.name }}{% if event.place_alt %} , {{ event.place_alt }}{% endif %} +
      +
      +
      {% endif %}
      @@ -152,7 +160,20 @@ {% endfor %} {% endwith %} + {% else %} + {% if event.org %} + + {% for item in event.org_split %} +
      {% if forloop.counter == 1 %}{% trans 'Организатор' %}:{% endif %}
      + +
      + {{ item }} +
      + {% endfor %} + + {% endif %} {% endif %} + {% if event.web_page %}
      {% trans 'Веб-сайт' %}:
      diff --git a/templates/client/includes/exposition/exposition_object.html b/templates/client/includes/exposition/exposition_object.html index b2491d4a..18d2a2c7 100644 --- a/templates/client/includes/exposition/exposition_object.html +++ b/templates/client/includes/exposition/exposition_object.html @@ -19,7 +19,7 @@ {{ exposition.visitors }} {% endif %} {% if exposition.members %} - {{ exposition.members }} + {{ exposition.members }} {% endif %}
      @@ -59,6 +59,15 @@
      + {% else %} +
      +
      +
      + {{ exposition.country.name }}, {{ exposition.city.name }}{% if exposition.place_alt %} , {{ exposition.place_alt }}{% endif %} +
      +
      +
      + {% endif %}
      @@ -159,12 +168,17 @@ {% else %} {% if exposition.org %} -
      {% trans 'Организатор' %}:
      -
      - {{ exposition.org }} -
      + {% for item in exposition.org_split %} +
      {% if forloop.counter == 1 %}{% trans 'Организатор' %}:{% endif %}
      + +
      + {{ item }} +
      + {% endfor %} + {% endif %} {% endif %} + {% if exposition.web_page %}
      {% trans 'Веб-сайт' %}:
      diff --git a/templates/client/includes/exposition/exposition_services.html b/templates/client/includes/exposition/exposition_services.html index 519a9b37..5e9b936f 100644 --- a/templates/client/includes/exposition/exposition_services.html +++ b/templates/client/includes/exposition/exposition_services.html @@ -8,11 +8,7 @@
    • {% trans 'Устный переводчик' %}
    • - {% if exposition.country_id not in sng_countries %} -
    • - {% trans 'Бизнес-тур "под ключ"' %} -
    • - {% endif %} +
    • {% trans 'Заочное посещение' %}
    • diff --git a/templates/client/includes/services.html b/templates/client/includes/services.html index e7f1c499..de96a1b5 100644 --- a/templates/client/includes/services.html +++ b/templates/client/includes/services.html @@ -7,7 +7,6 @@ {% comment %}
    • {% trans 'Билеты на выставки' %}
    • {% endcomment %}
    • {% trans 'Заочное посещение' %}
    • {% trans 'Участие в выставках' %}
    • -
    • {% trans 'Посещение выставки' %}
    \ No newline at end of file diff --git a/templates/client/index.html b/templates/client/index.html index 04cfcfd2..96882fb3 100644 --- a/templates/client/index.html +++ b/templates/client/index.html @@ -58,11 +58,17 @@
    {% block menu_banner %} - {% if False|fourth %} - + {% comment %} + {% if False|random3 == 1 %} + {% else %} - + {% if False|random3 == 2 %} + + {% else %} + + {% endif %} {% endif %} + {% endcomment %} {% endblock %}
    @@ -88,7 +94,7 @@ {% comment %}