diff --git a/.gitignore b/.gitignore index cb627fc4..3fc5210e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ Thumbs.db npm-debug.log /proj/local.py + + diff --git a/accounts/edit_forms.py b/accounts/edit_forms.py index ee602621..14f2860e 100644 --- a/accounts/edit_forms.py +++ b/accounts/edit_forms.py @@ -60,17 +60,22 @@ class HomeForm(forms.ModelForm): class WorkForm(forms.ModelForm): position = forms.CharField(label=_(u'Укажите вашу должность'), required=False, widget=forms.TextInput()) + company = forms.CharField(label=_(u'Укажите вашу компанию'), required=False, + widget=forms.HiddenInput(attrs={'class': 'select2'})) - company = forms.CharField(label=_(u'Место работы'), widget=forms.HiddenInput(attrs={'class': 'select2'})) def __init__(self, *args, **kwargs): super(WorkForm, self).__init__(*args, **kwargs) if self.instance.company: self.fields['company'].widget = forms.HiddenInput(attrs={'class': 'select2', 'data-init-text': self.instance.company.name}) + + class Meta: model = User fields = ('position', 'company') def clean_company(self): + if not self.cleaned_data.get('company'): + return None try: return Company.objects.get(id=self.cleaned_data['company']) except Company.DoesNotExist: @@ -87,9 +92,26 @@ class AboutCompanyForm(forms.ModelForm): class PhoneForm(forms.ModelForm): phone = forms.CharField(label=_(u'Контактный телефон'), required=False) + show_phone = forms.BooleanField(label=_(u'Контактный телефон'), required=False) + class Meta: model = Profile - fields = ('phone',) + fields = ('phone', 'show_phone') + + def clean_phone(self): + phone = self.cleaned_data['phone'] + if not phone: + return + + deduct = ('-','(',')','.',' ', '+') + for elem in deduct: + phone = phone.replace(elem, '') + if phone.isdigit(): + return phone + else: + raise forms.ValidationError(_(u'Введите правильный телефон')) + + class EmailForm(forms.ModelForm): email = forms.EmailField(label=_(u'Ваш e-mail'), required=False) diff --git a/accounts/forms.py b/accounts/forms.py index ede4846e..00c26f2f 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -218,10 +218,10 @@ class EmailAnnouncementForm(forms.Form): class RegistrationCompleteForm(forms.ModelForm): - country = forms.ChoiceField(label='Страна', choices=[(c.id, c.name) for c in Country.objects.all()], + country = forms.ModelChoiceField(label='Страна', queryset= Country.objects.all(), widget=forms.Select(attrs={'class': 'select2'})) city = forms.CharField(label='Город', widget=forms.HiddenInput()) - url = forms.CharField(widget=forms.TextInput(attrs={'placeholder': _(u'адрес страны(обязательно)')})) + url = forms.CharField(widget=forms.TextInput(attrs={'placeholder': _(u'url(обязательно)')})) code_country = forms.ChoiceField(label=_(u'код страны'), initial='70', choices=[(str(c.phone_code), '+'+str(c.phone_code)) for c in Country.objects.all() if c.phone_code is not None], @@ -254,12 +254,6 @@ class RegistrationCompleteForm(forms.ModelForm): return None - def clean_country(self): - try: - return Country.objects.get(id=self.cleaned_data['country']) - except City.DoesNotExist: - return None - def clean_url(self): url = self.cleaned_data['url'] if not is_latin(url): @@ -317,18 +311,14 @@ class FeedFilterForm(forms.Form): th = forms.MultipleChoiceField(label=_(u'Тематика'), choices=[(item.id, item.name) for item in Theme.active.all()], required=False, widget=forms.CheckboxSelectMultiple()) tg = forms.CharField(label=_(u'Теги'), required=False, widget=forms.CheckboxSelectMultiple()) - area = forms.MultipleChoiceField(label=_(u'Регион'), choices=[(item.id, item.name) for item in Area.objects.all_sorted()], + area = forms.MultipleChoiceField(label=_(u'Регион'), choices=[(item.id, item.name) for item in Area.objects.language().all()], required=False, widget=forms.CheckboxSelectMultiple()) co = forms.MultipleChoiceField(label=_(u'Страна'), required=False, widget=forms.CheckboxSelectMultiple(), - choices=[(item.id, item.name) for item in Country.objects.select_related('exposition_country')\ - .filter(exposition_country__country__isnull=False, translations__language_code=translation.get_language())\ - .order_by('translations__name').distinct()] + choices=[(item.id, item.name) for item in Country.objects.expo_countries()] ) ci = forms.MultipleChoiceField(label=_(u'Город'), required=False, widget=forms.CheckboxSelectMultiple(), - choices=[(item.id, item.name) for item in City.objects.select_related('exposition_city')\ - .filter(exposition_city__city__isnull=False, translations__language_code=translation.get_language())\ - .order_by('translations__name').distinct()] + choices=[(item.id, item.name) for item in City.used.expo_cities()] ) fr = forms.DateField(required=False, diff --git a/accounts/models.py b/accounts/models.py index 57d758ee..1a68fa90 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -132,8 +132,7 @@ class User(AbstractBaseUser, PermissionsMixin): translator = models.ForeignKey('translator.Translator', verbose_name='Переводчик', blank=True, null=True, unique=True, on_delete=models.PROTECT, related_name='user') - company = models.ForeignKey('company.Company', blank=True, null=True, - on_delete=models.PROTECT, related_name='users') + company = models.ForeignKey('company.Company', blank=True, null=True, related_name='users') position = models.CharField(verbose_name='Должность', max_length=255, blank=True) objects = UserManager() @@ -223,6 +222,23 @@ class User(AbstractBaseUser, PermissionsMixin): """ return self.seminar_users.language().select_related('country', 'city').all() + def remove_from_calendar(self, data): + expo = data['expo'] + conf = data['conf'] + seminar = data['seminar'] + webinar = data['webinar'] + calendar = self.calendar + if expo: + calendar.expositions.remove(*expo) + if conf: + calendar.conferences.remove(*conf) + if seminar: + calendar.seminars.remove(*seminar) + if webinar: + calendar.webinars.remove(*webinar) + + + class Profile(models.Model): @@ -237,15 +253,16 @@ class Profile(models.Model): on_delete=models.PROTECT) about_company = models.TextField(verbose_name=_(u'Описание компании'), blank=True) - phone = models.BigIntegerField(verbose_name='Телефон', blank=True, null=True) + phone = models.BigIntegerField(verbose_name=_(u'Телефон'), blank=True, null=True) + show_phone = models.NullBooleanField(verbose_name=_(u'Показывать телефон'), blank=True, null=True, default=1) web_page = models.URLField(verbose_name='Вебсайт',blank=True) about = models.TextField(verbose_name='О себе', blank=True) avatar = models.ImageField(verbose_name='Фото', upload_to='accounts/avatar/', blank=True) skype = models.CharField(blank=True, max_length=255) - facebook = models.URLField(verbose_name=_(u'Facebook'), blank=True) - twitter = models.URLField(verbose_name=_(u'Twitter'), blank=True) - linkedin = models.URLField(verbose_name=_(u'LinkedIn'), blank=True) - vk = models.URLField(verbose_name=_(u'В контакте'), blank=True) + facebook = models.URLField(verbose_name=_(u'Facebook'), blank=True, max_length=255) + twitter = models.URLField(verbose_name=_(u'Twitter'), blank=True,max_length=255) + linkedin = models.URLField(verbose_name=_(u'LinkedIn'), blank=True, max_length=255) + vk = models.URLField(verbose_name=_(u'В контакте'), blank=True, max_length=255) # meta title = models.CharField(max_length=255, blank=True) @@ -385,86 +402,10 @@ def create_user_inf(sender, instance, created, **kwargs): calculate_rating(instance) -post_save.connect(create_user_inf, sender=User) - -#need import after User Model, because User imported in "organiser.models" -#from organiser.models import Organiser - -''' -def create_profiles(sender, **kw): - """ - create Translator profile if "is_translator" field in User model true - if it's false delete Translator profile connected to User - - create Organiser profile if "is_organiser" field in User model true - if it's false delete Organiser profile connected to User - """ - user = kw["instance"] - - if user.is_translator and not user.translator.all(): - #check flag is_translator and if translator profile already exist - translator = TranslatorProfile(user=user) - translator.save() - - if not user.is_translator: - TranslatorProfile.objects.filter(user = user).delete() - - - if user.is_organiser and not user.organiser.all(): - #check flag is_organiser and if organiser profile already exist - organiser = Organiser(user=user) - - if user.country: - organiser.country = user.country - - if user.city: - organiser.city = user.city - - organiser.save() - - - data = {'name_ru':user.get_full_name()} - - zero_fields = {} - fill_trans_fields_all(Organiser, organiser, data, None, zero_fields) - #populate empty fields and fields which was already populated - organiser_id = getattr(organiser, 'id') - populate_all(Organiser, data, organiser_id, zero_fields) - - if not user.is_organiser: - Organiser.objects.filter(user = user).delete() - - -post_save.connect(create_profiles, sender=User) -''' - -""" -class MyUserAuthBackend(object): - def check_md5_password(self, db_password, supplied_password): - return md5(supplied_password).hex_digest(), db_password - - def authenticate(self, username=None, password=None, **kwargs): - # Authenticate a user based on email address as the user name. - UserModel = get_user_model() - if username is None: - username = kwargs.get(UserModel.USERNAME_FIELD) - try: - user = UserModel._default_manager.get_by_natural_key(username) - if check_password(password, user.password): -# user.set_password(password) -# user.save() - return user - #if user.check_password(password): - # return user - except UserModel.DoesNotExist: - return None - +def post_profile(sender, instance, created, **kwargs): + user = instance.user + calculate_rating(user) +post_save.connect(create_user_inf, sender=User) +post_save.connect(post_profile, sender=Profile) - def get_user(self, user_id): - try: - UserModel = get_user_model() - return UserModel._default_manager.get(pk=user_id) - except UserModel.DoesNotExist: - return None -""" \ No newline at end of file diff --git a/accounts/urls.py b/accounts/urls.py index e7842ee5..ffd93efa 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -15,6 +15,7 @@ urlpatterns = patterns('', url(r'^profile/$', login_required(ProfileView.as_view())), url(r'^profile/company/$', login_required(ProfileCompanyView.as_view())), url(r'^profile/settings/$', login_required(SettingsView.as_view())), + url(r'^profile/calendar/remove/$', 'accounts.views.remove_from_calendar'), url(r'^profile/calendar/$', login_required(CalendarView.as_view())), url(r'^profile/feed/page/(?P\d+)/$', Feed.as_view()), url(r'^profile/feed/$', login_required(Feed.as_view())), diff --git a/accounts/user_catalog_urls.py b/accounts/user_catalog_urls.py index 6ebf7656..60fdaf9d 100644 --- a/accounts/user_catalog_urls.py +++ b/accounts/user_catalog_urls.py @@ -3,14 +3,14 @@ from django.contrib.auth.decorators import login_required from views import SettingsView, ProfileView, CalendarView, UserView, UserExpositionsView, UserConferenceView, UserSeminarView urlpatterns = patterns('', - url(r'^(?P.*)/expositions/(?P\d+)/$', UserExpositionsView.as_view()), - url(r'^(?P.*)/expositions/$', UserExpositionsView.as_view()), + url(r'^(?P.*)/expositions/(?P\d+)/$', UserExpositionsView.as_view(), {'meta_id': 72}), + url(r'^(?P.*)/expositions/$', UserExpositionsView.as_view(), {'meta_id': 72}), url(r'^(?P.*)/seminars/(?P\d+)/$', UserSeminarView.as_view()), url(r'^(?P.*)/seminars/$', UserSeminarView.as_view()), - url(r'^(?P.*)/conferences/(?P\d+)/$', UserConferenceView.as_view()), - url(r'^(?P.*)/conferences/$', UserConferenceView.as_view()), + url(r'^(?P.*)/conferences/(?P\d+)/$', UserConferenceView.as_view(), {'meta_id': 73}), + url(r'^(?P.*)/conferences/$', UserConferenceView.as_view(), {'meta_id': 73}), url(r'^(?P.*)/events/(?P\d+)/$', UserView.as_view()), url(r'^(?P.*)/events/$', UserView.as_view()), - url(r'^(?P.*)/$', UserView.as_view()), + url(r'^(?P.*)/$', UserView.as_view(), {'meta_id': 71}), ) diff --git a/accounts/views.py b/accounts/views.py index f39782ac..e4eb1243 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import dateutil.relativedelta as rdelta import json, datetime import calendar as python_calendar from django.shortcuts import get_object_or_404 @@ -55,7 +56,7 @@ class CalendarView(TemplateView): """ context = super(CalendarView, self).get_context_data(**kwargs) - now = timezone.now().replace(microsecond=0, second=0, minute=0, hour=0) + now = datetime.datetime.now().replace(microsecond=0, second=0, minute=0, hour=0) context['current_day'] = now year = self.request.GET.get('year') @@ -69,8 +70,8 @@ class CalendarView(TemplateView): # events in current months number_of_days = python_calendar.monthrange(now.year, now.month)[1] # number of days in current month - days = [timezone.make_aware(datetime.datetime(now.year, now.month, i+1), timezone.get_default_timezone()) for i in range(number_of_days)] - context['days'] = days + days = [datetime.datetime(now.year, now.month, i+1) for i in range(number_of_days)] + #context['days'] = days calendar = self.request.user.calendar # events in current month @@ -78,17 +79,33 @@ class CalendarView(TemplateView): else: number_of_days = python_calendar.monthrange(year, month)[1] - days = [timezone.make_aware(datetime.datetime(year, month, i+1), timezone.get_default_timezone()) for i in range(number_of_days)] + days = [datetime.datetime(year, month, i+1) for i in range(number_of_days)] # number of days in current month - context['days'] = days + #context['days'] = days calendar = self.request.user.calendar now = now.replace(year=year, month=month, day=1) # events in current month context['events'] = calendar.events_by_month(now) + # add days from previous mondey to next sunday + + first_day = days[0] + if first_day.weekday() != 0: + past_monday = first_day + rdelta.relativedelta(days=-1, weekday=rdelta.MO(-1)) + a = [past_monday + datetime.timedelta(days=x) for x in range((first_day - past_monday).days)] + days = a + days + + + last_day = days[-1] + + if last_day != 6: + next_sunday = last_day + rdelta.relativedelta(days=1, weekday=rdelta.SU(+1)) + b = [last_day + datetime.timedelta(days=x+1) for x in range((next_sunday - last_day).days)] + days += b events = context['events'] - days = context['days'] + context['days'] = days + #days = context['days'] event_in_day = False counter = 0 dates_with_events = [] @@ -190,21 +207,27 @@ class ProfileCompanyView(TemplateView): - -class UserView(TemplateView): +from meta.views import MetadataMixin +class UserView(MetadataMixin, TemplateView): """ display user information for another users """ - template_name = 'accounts/user.html' + template_name = 'client/accounts/user.html' - def get_context_data(self, **kwargs): - context = super(UserView, self).get_context_data(**kwargs) + def get_user(self): url = self.kwargs.get('url') + try: url = int(url) user = get_object_or_404(User, id=url) except ValueError: user = get_object_or_404(User, url=url) + self.kwargs['user_full_name'] = user.get_full_name() + return user + + def get_context_data(self, **kwargs): + user = self.get_user() + context = super(UserView, self).get_context_data(**kwargs) if user == self.request.user: profile = user.profile @@ -213,11 +236,9 @@ class UserView(TemplateView): 'home_form': HomeForm(instance=profile), 'work_form': WorkForm(instance=user), 'about_company_form': AboutCompanyForm(instance=profile), 'phone_form': PhoneForm(instance=profile), 'email_form': EmailForm(instance=user), 'web_page_form': WebPageForm(instance=profile), - 'social_form': SocialForm(instance=profile), 'about_form': AboutForm(instance=profile) + 'social_form': SocialForm(instance=profile), 'about_form': AboutForm(instance=profile), + 'company_form': CreateCompanyForm() } - if not user.company: - company_form = {'company_form': CreateCompanyForm()} - context.update(company_form) context.update(profile_forms) @@ -246,8 +267,8 @@ class BaseProfileView(ProfileInvalidView): def form_valid(self, form): profile = self.request.user.profile form = self.form_class(self.request.POST, instance=profile) - form.save() - response = {'success': True} + profile = form.save() + response = {'success': True, 'rating': profile.user.rating} return HttpResponse(json.dumps(response), content_type='application/json') class WorkView(ProfileInvalidView): @@ -260,10 +281,10 @@ class WorkView(ProfileInvalidView): user = self.request.user form = self.form_class(self.request.POST, instance=user) user = form.save() - company = user.company - + #company = user.company - response = {'success': True, 'url':company.get_permanent_url()} + #response = {'success': True, 'url':company.get_permanent_url()} + response = {'success': True, 'rating': user.rating} return HttpResponse(json.dumps(response), content_type='application/json') @@ -278,10 +299,10 @@ class AvatarView(BaseProfileView): def form_valid(self, form): profile = self.request.user.profile form = self.form_class(self.request.POST, self.request.FILES, instance=profile) - form.save() + profile = form.save() if self.request.is_ajax(): - im = get_thumbnail(profile.avatar, '100x100', crop='center') - response = {'success': True, 'url': im.url} + im = get_thumbnail(profile.avatar, '100x100', format="PNG") + response = {'success': True, 'url': im.url, 'rating': profile.user.rating} return HttpResponse(json.dumps(response), content_type='application/json') else: return HttpResponseRedirect('/profile/') @@ -337,8 +358,8 @@ class NameView(ProfileInvalidView): def form_valid(self, form): user = self.request.user form = self.form_class(self.request.POST, instance=user) - form.save() - response = {'success': True} + user = form.save() + response = {'success': True, 'rating': user.rating} return HttpResponse(json.dumps(response), content_type='application/json') @@ -373,7 +394,7 @@ class UserEventView(ListView): context['event_type'] = self.event_type return context -class UserExpositionsView(UserEventView): +class UserExpositionsView(MetadataMixin, UserEventView): """ return template with list of expos that user joined """ @@ -383,10 +404,11 @@ class UserExpositionsView(UserEventView): url = self.kwargs.get('url') user = get_user(url) self.obj = user + self.kwargs['user_full_name'] = user.get_full_name() return user.get_expos() -class UserConferenceView(UserEventView): +class UserConferenceView(MetadataMixin, UserEventView): """ return template with list of confs that user joined """ @@ -396,6 +418,7 @@ class UserConferenceView(UserEventView): url = self.kwargs.get('url') user = get_user(url) self.obj = user + self.kwargs['user_full_name'] = user.get_full_name() return user.get_confs() class UserSeminarView(UserEventView): @@ -441,7 +464,7 @@ def change_password(request): from django.views.generic.edit import FormMixin class Feed(ListView): template_name = 'client/accounts/feed.html' - paginate_by = 5 + paginate_by = 10 model = Exposition filter_form = FeedFilterForm success_url = '/profile/feed/' @@ -465,4 +488,24 @@ class Feed(ListView): user = self.request.user filter_form = self.filter_form(user=user) context['filter_form'] = filter_form - return context \ No newline at end of file + return context + + +@login_required +def remove_from_calendar(request): + if request.GET: + expo = request.GET.get('expo') + conf = request.GET.get('conf') + seminar = request.GET.get('seminar') + webinar = request.GET.get('webinar') + + data = {'expo': expo if expo is None else json.loads(expo), + 'conf': conf if conf is None else json.loads(conf), + 'seminar': seminar if seminar is None else json.loads(seminar), + 'webinar': webinar if webinar is None else json.loads(webinar)} + user = request.user + user.remove_from_calendar(data) + + return HttpResponse(json.dumps({'success': True}), content_type='application/json') + else: + return Http404 \ No newline at end of file diff --git a/article/admin.py b/article/admin.py index 18722821..62f22d21 100644 --- a/article/admin.py +++ b/article/admin.py @@ -9,7 +9,7 @@ from django.contrib.contenttypes.models import ContentType from forms import ArticleForm, ArticleDeleteForm, Article, NewsForm from theme.models import Tag from file.models import FileModel, TmpFile -from file.forms import FileModelForm +from file.forms import FileModelForm, FileForm #custom views from functions.custom_views import objects_list, add_object_with_file, delete_object @@ -180,7 +180,13 @@ class BlogView(FormView): def get_context_data(self, **kwargs): context = super(BlogView, self).get_context_data(**kwargs) self.set_obj() + + context['article'] = self.obj + if context['article']: + context['file_form'] = FileForm(initial={'model': 'article.Article'}) + context['files'] = FileModel.objects.filter(content_type=ContentType.objects.get_for_model(context['article']), + object_id=getattr(context['article'], 'id')) context['languages'] = settings.LANGUAGES return context @@ -188,6 +194,7 @@ class BlogView(FormView): class NewsList(ListView): model = Article template_name = 'article/article_admin_list.html' + paginate_by = 20 def get_queryset(self): return self.model.objects.news() diff --git a/article/forms.py b/article/forms.py index 44fcdad8..0f7c8537 100644 --- a/article/forms.py +++ b/article/forms.py @@ -4,6 +4,7 @@ from django.conf import settings from ckeditor.widgets import CKEditorWidget from django.core.exceptions import ValidationError from django.forms.util import ErrorList +from django.utils.translation import ugettext as _ #functions from functions.translate import fill_with_signal from functions.files import check_tmp_files @@ -226,4 +227,47 @@ class BlogForm(forms.ModelForm): widget=forms.TextInput(attrs={'style':'width: 550px'})) self.fields['descriptions_%s' % code] = forms.CharField(label='Кейвордс', required=False, max_length=255, widget=forms.TextInput(attrs={'style':'width: 550px'})) -""" \ No newline at end of file +""" + + + +class ArticleFilterForm(forms.Form): + theme = forms.MultipleChoiceField(label=_(u'Тематика:'), required=False, + choices=[(item.id, item.name) for item in Theme.objects.language().all()]) + tag = forms.CharField(label=_(u'Теги:'), widget=forms.HiddenInput(), required=False) + + ''' + + def __init__(self, *args, **kwargs): + """ + create dynamical translated fields fields + """ + super(ArticleFilterForm, self).__init__(*args, **kwargs) + ids = [item['theme_id'] for item in list(Article.objects.blogs().values('theme_id').distinct())] + self.fields['theme'] = forms.MultipleChoiceField(label=_(u'Тематика:'), required=False, + choices=[(item.id, item.name) for item in Theme.objects.language().filter(id__in=ids)]) + ''' + +class BlogFilterForm(forms.Form): + tag = forms.CharField(label=_(u'Теги:'), widget=forms.HiddenInput(), required=False) + + def __init__(self, *args, **kwargs): + """ + create dynamical translated fields fields + """ + super(BlogFilterForm, self).__init__(*args, **kwargs) + ids = [item['theme'] for item in list(Article.objects.blogs().values('theme').distinct())] + self.fields['theme'] = forms.MultipleChoiceField(label=_(u'Тематика:'), required=False, + choices=[(item.id, item.name) for item in Theme.objects.language().filter(id__in=ids)]) + +class NewsFilterForm(forms.Form): + tag = forms.CharField(label=_(u'Теги:'), widget=forms.HiddenInput(), required=False) + + def __init__(self, *args, **kwargs): + """ + create dynamical translated fields fields + """ + super(NewsFilterForm, self).__init__(*args, **kwargs) + ids = [item['theme'] for item in list(Article.objects.news().values('theme').distinct())] + self.fields['theme'] = forms.MultipleChoiceField(label=_(u'Тематика:'), required=False, + choices=[(item.id, item.name) for item in Theme.objects.language().filter(id__in=ids)]) \ No newline at end of file diff --git a/article/models.py b/article/models.py index 6f65aaa3..8cdf6833 100644 --- a/article/models.py +++ b/article/models.py @@ -1,16 +1,22 @@ # -*- coding: utf-8 -*- import copy from django.db import models +from django.contrib.contenttypes import generic from django.utils.translation import ugettext_lazy as _ +from django.utils import translation from django.utils.timezone import now from hvad.models import TranslatableModel, TranslatedFields, TranslationManager from django.utils.html import strip_tags from sorl.thumbnail import ImageField from functions.url_utils import slugify, unique_slug from functions.model_utils import base_concrete_model +from functions.form_check import translit_with_separator +from django.core.cache import cache + class ArticleManager(TranslationManager): + cache_time = 60 def safe_get(self, **kwargs): model = self.model try: @@ -23,14 +29,38 @@ class ArticleManager(TranslationManager): return queryset of news """ model = self.model - return model.objects.filter(type=model.news) + return self.language().filter(type=model.news) def blogs(self): """ return queryset of blogs """ model = self.model - return model.objects.filter(type=model.blog) + return self.language().filter(type=model.blog) + + def main_page_news(self): + lang = translation.get_language() + key = 'main_page_news_%s'%lang + cached_news = cache.get(key) + if cached_news: + return cached_news + else: + news = list(self.news().filter(publish_date__isnull=False).order_by('-main_page', '-publish_date')[:3]) + cache.set(key, news, self.cache_time) + return news + + def main_page_blogs(self): + lang = translation.get_language() + key = 'main_page_blogs_%s'%lang + cached_blogs = cache.get(key) + if cached_blogs: + return cached_blogs + else: + blogs = list(self.blogs().filter(publish_date__isnull=False).order_by('-main_page', '-publish_date')[:3]) + cache.set(key, blogs, self.cache_time) + return blogs + + return list(self.blogs().filter(publish_date__isnull=False).order_by('-main_page', '-publish_date')[:3]) class Article(TranslatableModel): """ @@ -73,23 +103,27 @@ class Article(TranslatableModel): gen_description = models.BooleanField(_("Generate description"), help_text=_("If checked, the description will be automatically " "generated from content. Uncheck if you want to manually " - "set a custom description."), default=True) + "set a custom description."), default=False) # published = models. - created = models.DateTimeField(auto_now_add=True) + created = models.DateTimeField() modified = models.DateTimeField(auto_now=True) #translated fields translations = TranslatedFields( - main_title = models.CharField(max_length=100), + main_title = models.CharField(max_length=255), preview = models.TextField(), - description = models.TextField(), + description = models.TextField(blank=False), #-----meta title = models.CharField(max_length=255, blank=True), descriptions = models.CharField(max_length=255, blank=True), keywords = models.CharField(max_length=255, blank=True), ) + files = generic.GenericRelation('file.FileModel', content_type_field='content_type', object_id_field='object_id') + class Meta: + ordering = ['-created'] + def __unicode__(self): return self.lazy_translation_getter('main_title', self.pk) @@ -121,8 +155,8 @@ class Article(TranslatableModel): self.slug = self.generate_unique_slug() #Set the description field on save. - if self.gen_description: - self.description = strip_tags(self.description_from_content()) + #if self.gen_description: + # self.description = strip_tags(self.description_from_content()) super(Article, self).save(*args, **kwargs) def description_from_content(self): @@ -140,7 +174,9 @@ class Article(TranslatableModel): # slug lookup. concrete_model = base_concrete_model(Article, self) slug_qs = concrete_model.objects.exclude(id=self.id) - return unique_slug(slug_qs, "slug", self.get_slug()) + slug = unique_slug(slug_qs, "slug", self.get_slug()) + slug = translit_with_separator(slug) + return slug def get_slug(self): """ @@ -184,60 +220,6 @@ class Article(TranslatableModel): """ return self._get_next_or_previous_by_publish_date(False, **kwargs) - def clone(self): - """ - Return an identical copy of the instance with a new ID. - """ - if not self.pk: - raise ValueError('Instance must be saved before it can be cloned.') - - duplicate = copy.copy(self) - # Setting pk to None. Django thinking this is a new object. - duplicate.pk = None - # url must be unique - duplicate.url += '_copy' - if Article.objects.safe_get(url=duplicate.url): - #already has copy this instance - return - - 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.save() - # but lost all ManyToMany relations and Translations. - ''' - # 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) - - # copy translations - languages = self.get_available_languages() - ignore_fields = ['id', 'master', 'language_code'] - - for code in languages: - duplicate.translate(code) - tr = self._meta.translations_model.objects.get(language_code = code,master__id=self.pk) - for field in duplicate._translated_field_names: - - if field in ignore_fields: - continue - - setattr(duplicate, field, getattr(tr, field)) - - duplicate.save() - ''' - - return duplicate def admin_url(self): if self.type == 1: @@ -247,9 +229,36 @@ class Article(TranslatableModel): def get_permanent_url(self): if self.type == 1: - return '/blogs/%s'%self.slug + return '/blogs/%s/'%self.slug elif self.type == 2: - return '/news/%s'%self.slug + return '/news/%s/'%self.slug + + def get_blog_preview(self): + + preview = self.files.filter(purpose='preview') + if preview: + return preview[0] + else: + return None + + def get_blog_preview2(self): + + preview = self.files.filter(purpose='preview2') + if preview: + return preview[0] + else: + return None + + def get_catalog(self): + if self.type == 1: + return '/blogs/' + elif self.type == 2: + return '/news/' + + def similar(self): + themes = [item ['id'] for item in self.theme.all().values('id')] + return list(Article.objects.language().exclude(id=self.id).filter(type=self.type, publish_date__isnull=False, theme__in=themes).distinct().order_by('-publish_date')[:3]) + from django.db.models.signals import post_save from functions.signal_handlers import post_save_handler diff --git a/article/urls.py b/article/urls.py index 84a18675..a0faf232 100644 --- a/article/urls.py +++ b/article/urls.py @@ -1,10 +1,22 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, url -from views import BlogList, NewsList, BlogDetail, NewsDetail +from views import BlogList, NewsList, BlogDetail, NewsDetail, NewsTagCatalog, BlogsTagCatalog urlpatterns = patterns('', - url(r'blogs/$', BlogList.as_view()), - url(r'news/$', NewsList.as_view()), - url(r'blogs/(?P.*)$', BlogDetail.as_view()), - url(r'news/(?P.*)$', NewsDetail.as_view()), + url(r'^blogs/tag/(?P.*)/page/(?P\d+)/$', BlogsTagCatalog.as_view(), {'meta_id':75}), + url(r'^blogs/page/(?P\d+)/$', BlogList.as_view(), {'meta_id':79}), + url(r'^blogs/tag/(?P.*)/$', BlogsTagCatalog.as_view(), {'meta_id':75}), + url(r'^blogs/$', BlogList.as_view(), {'meta_id':79}), + + + url(r'^news/tag/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', NewsTagCatalog.as_view(), {'meta_id':77}), + url(r'^news/tag/(?P.*)/(?P\d+)/page/(?P\d+)/$', NewsTagCatalog.as_view(), {'meta_id':76}), + url(r'^news/tag/(?P.*)/page/(?P\d+)/$', NewsTagCatalog.as_view(), {'meta_id':74}), + url(r'^news/tag/(?P.*)/(?P\d+)/(?P.*)/$', NewsTagCatalog.as_view(), {'meta_id':77}), + url(r'^news/tag/(?P.*)/(?P\d+)/$', NewsTagCatalog.as_view(), {'meta_id':76}), + url(r'^news/tag/(?P.*)/$', NewsTagCatalog.as_view(), {'meta_id':74}), + url(r'^news/page/(?P\d+)/$', NewsList.as_view(), {'meta_id':78}), + url(r'^news/$', NewsList.as_view(), {'meta_id':78}), + url(r'^blogs/(?P.*)/$', BlogDetail.as_view(), {'meta_id':19}), + url(r'^news/(?P.*)/$', NewsDetail.as_view(), {'meta_id':19}), ) diff --git a/article/views.py b/article/views.py index 862e73fb..4b421db2 100644 --- a/article/views.py +++ b/article/views.py @@ -1,10 +1,18 @@ +# -*- coding: utf-8 -*- +import json from django.views.generic import DetailView, ListView from django.http import HttpResponse from models import Article +from forms import ArticleFilterForm +from theme.models import Tag +from meta.views import MetadataMixin -class NewsList(ListView): + + +class NewsList(MetadataMixin, ListView): model = Article template_name = 'article/news_list.html' + paginate_by = 10 def get_queryset(self): if self.request.GET: @@ -14,22 +22,47 @@ class NewsList(ListView): qs = qs.filter(theme__id__in=themes) tags = self.request.GET.getlist('tag') + if u'' in tags: + tags.remove(u'') if tags: + tags = tags[0].split(',') qs = qs.filter(tag__id__in=tags) return qs else: - return self.model.objects.news() + return self.model.objects.news().filter(publish_date__isnull=False).order_by('-publish_date') -class NewsDetail(DetailView): + def get_context_data(self, **kwargs): + context = super(NewsList, self).get_context_data(object_list=self.object_list) + if self.request.GET: + filter_form = ArticleFilterForm(self.request.GET) + tags = self.request.GET.getlist('tag') + if u'' in tags: + tags.remove(u'') + if tags: + tags = tags[0].split(',') + tag_qs = Tag.objects.filter(id__in=tags) + tags = [{'id': str(tag.id), 'text': tag.name} for tag in tag_qs] + filter_form.fields['tag'].widget.attrs['data-predifined'] = json.dumps(tags) + filter_form.fields['tag'].widget.attrs['value'] = '' + else: + filter_form = ArticleFilterForm() + + context['article_filter_form'] = filter_form + return context + + + +class NewsDetail(MetadataMixin, DetailView): model = Article slug_field = 'slug' template_name = 'article/news.html' -class BlogList(ListView): +class BlogList(MetadataMixin, ListView): model = Article template_name = 'article/blog_list.html' + paginate_by = 10 def get_queryset(self): if self.request.GET: @@ -40,16 +73,136 @@ class BlogList(ListView): qs = qs.filter(theme__id__in=themes) tags = self.request.GET.getlist('tag') + if u'' in tags: + tags.remove(u'') if tags: + tags = tags[0].split(',') qs = qs.filter(tag__id__in=tags) return qs else: return self.model.objects.blogs() + def get_context_data(self, **kwargs): + context = super(BlogList, self).get_context_data(object_list=self.object_list) + if self.request.GET: + filter_form = ArticleFilterForm(self.request.GET) + tags = self.request.GET.getlist('tag') + if u'' in tags: + tags.remove(u'') + if tags: + tags = tags[0].split(',') + tag_qs = Tag.objects.filter(id__in=tags) + tags = [{'id': str(tag.id), 'text': tag.name} for tag in tag_qs] + filter_form.fields['tag'].widget.attrs['data-predifined'] = json.dumps(tags) + filter_form.fields['tag'].widget.attrs['value'] = '' + else: + filter_form = ArticleFilterForm() + + context['article_filter_form'] = filter_form + return context + -class BlogDetail(DetailView): +class BlogDetail(MetadataMixin, DetailView): model = Article slug_field = 'slug' - template_name = 'article/article.html' \ No newline at end of file + template_name = 'article/article.html' + + +from exposition.views import ExpoCatalog +from django.conf import settings +from django.shortcuts import get_object_or_404 +from django.utils.translation import ugettext as _ + +class NewsTagCatalog(MetadataMixin, ListView): + model = Article + template_name = 'client/article/catalog.html' + catalog_url = '/news/tag/' + filter_object = None + year = None + month = None + + def get_queryset(self): + slug = self.kwargs.get('slug') + tag = get_object_or_404(Tag, url=slug) + self.kwargs['tag'] = tag + self.filter_object = tag + qs = Article.objects.news().filter(tag=tag) + year = self.kwargs.get('year') + + if year: + qs = qs.filter(publish_date__year=year) + # info for breadscrumbs + self.year = {'text': year, 'link': '%s%s/%s/'%(self.catalog_url, self.filter_object.url, year)} + + month = self.kwargs.get('month') + + monthes = {'jan': {'value': 1, 'name': _(u'Январь')}, 'feb': {'value': 2, 'name': _(u'Февраль')}, + 'mar': {'value': 3, 'name': _(u'Март')}, 'apr': {'value': 4, 'name': _(u'Апрель')}, + 'may': {'value': 5, 'name': _(u'Май')}, 'jun': {'value': 6, 'name': _(u'Июнь')}, + 'jul': {'value': 7, 'name': _(u'Июль')}, 'aug': {'value': 8, 'name': _(u'Август')}, + 'sep': {'value': 9, 'name': _(u'Сентябрь')}, 'oct': {'value': 10, 'name': _(u'Октябрь')}, + 'nov': {'value': 11, 'name': _(u'Ноябрь')}, 'dec': {'value': 12, 'name': _(u'Декабрь')}} + + if month and monthes.get(month): + qs = qs.filter(publish_date__month=monthes[month]['value']) + + self.month = {'text': monthes[month]['name'], 'link': '%s%s/%s/%s/'%(self.catalog_url, self.filter_object.url, year, month)} + return qs + + + def get_context_data(self, **kwargs): + context = super(NewsTagCatalog, self).get_context_data(**kwargs) + context['filter_object'] = self.filter_object + context['year'] = self.year + context['month'] = self.month + context['catalog_url'] = self.catalog_url + return context + + + +class BlogsTagCatalog(MetadataMixin, ListView): + model = Article + template_name = 'client/article/catalog.html' + catalog_url = '/blogs/tag/' + filter_object = None + year = None + month = None + + def get_queryset(self): + slug = self.kwargs.get('slug') + tag = get_object_or_404(Tag, url=slug) + self.kwargs['tag'] = tag + self.filter_object = tag + qs = Article.objects.blogs().filter(tag=tag) + year = self.kwargs.get('year') + + if year: + qs = qs.filter(publish_date__year=year) + # info for breadscrumbs + self.year = {'text': year, 'link': '%s%s/%s/'%(self.catalog_url, self.filter_object.url, year)} + + month = self.kwargs.get('month') + + monthes = {'jan': {'value': 1, 'name': _(u'Январь')}, 'feb': {'value': 2, 'name': _(u'Февраль')}, + 'mar': {'value': 3, 'name': _(u'Март')}, 'apr': {'value': 4, 'name': _(u'Апрель')}, + 'may': {'value': 5, 'name': _(u'Май')}, 'jun': {'value': 6, 'name': _(u'Июнь')}, + 'jul': {'value': 7, 'name': _(u'Июль')}, 'aug': {'value': 8, 'name': _(u'Август')}, + 'sep': {'value': 9, 'name': _(u'Сентябрь')}, 'oct': {'value': 10, 'name': _(u'Октябрь')}, + 'nov': {'value': 11, 'name': _(u'Ноябрь')}, 'dec': {'value': 12, 'name': _(u'Декабрь')}} + + if month and monthes.get(month): + qs = qs.filter(publish_date__month=monthes[month]['value']) + + self.month = {'text': monthes[month]['name'], 'link': '%s%s/%s/%s/'%(self.catalog_url, self.filter_object.url, year, month)} + return qs + + + def get_context_data(self, **kwargs): + context = super(BlogsTagCatalog, self).get_context_data(**kwargs) + context['filter_object'] = self.filter_object + context['year'] = self.year + context['month'] = self.month + context['catalog_url'] = self.catalog_url + return context \ No newline at end of file diff --git a/city/admin.py b/city/admin.py index c09eec7c..adf383e3 100644 --- a/city/admin.py +++ b/city/admin.py @@ -56,7 +56,7 @@ def city_change(request, url): else: #fill form with data from database data = {'population' : c.population, 'phone_code' : c.phone_code, - 'city_id' : city_id} + 'city_id' : city_id, 'inflect':c.inflect} if c.country: data['country'] = c.country.id diff --git a/city/forms.py b/city/forms.py index d2f8ff62..86082213 100644 --- a/city/forms.py +++ b/city/forms.py @@ -33,6 +33,7 @@ class CityForm(forms.Form): phone_code = forms.CharField(label='Код города', required=False, 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) #field for comparing tmp files key = forms.CharField(required=False, widget=forms.HiddenInput()) # @@ -85,6 +86,7 @@ class CityForm(forms.Form): city.phone_code = data['phone_code'] city.population = data.get('population') + city.inflect = data['inflect'] if data.get('code_IATA'): city.code_IATA = Iata.objects.get(id=data['code_IATA'].id)# .id cause select uses queryset diff --git a/city/management/commands/city_slug.py b/city/management/commands/city_slug.py new file mode 100644 index 00000000..d60006a9 --- /dev/null +++ b/city/management/commands/city_slug.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +from django.core.management.base import BaseCommand, CommandError +from city.models import City +from country.models import Country +from functions.form_check import translit_with_separator +from django.db import IntegrityError + + +class Command(BaseCommand): + def handle(self, *args, **options): + + qs = City.objects.language('en').filter() + for c in qs: + url = translit_with_separator(c.name.encode('utf8')) + c.url = url + try: + c.save() + except IntegrityError: + continue + + print(c.url) + #print(qs.count()) \ No newline at end of file diff --git a/city/management/commands/city_update_from_old.py b/city/management/commands/city_update_from_old.py new file mode 100644 index 00000000..465d0930 --- /dev/null +++ b/city/management/commands/city_update_from_old.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +import MySQLdb +from MySQLdb.cursors import DictCursor +from django.core.management.base import BaseCommand, CommandError +from django.utils import translation +from country.models import City + + +class Command(BaseCommand): + def handle(self, *args, **options): + db = MySQLdb.connect(host="localhost", + user="kotzilla", + passwd="qazedc", + db="test2", + charset='utf8', + cursorclass=DictCursor) + cursor = db.cursor() + sql = """SELECT title, url, inflect + FROM old_expomap.products_places + WHERE parent_id > 0 """ + + + cursor.execute(sql) + result = cursor.fetchall() + for res in result: + name = res['title'] + url = res['url'] + inflect = res['inflect'] + City.objects.filter(translations__name=name).update(inflect=inflect, old_url=url) + print(name.encode('utf-8')) \ No newline at end of file diff --git a/city/models.py b/city/models.py index f2e312bf..77920a05 100644 --- a/city/models.py +++ b/city/models.py @@ -11,10 +11,13 @@ from service.models import Service from exposition.models import Exposition from place_exposition.models import PlaceExposition from organiser.models import Organiser +from conference.models import Conference +from seminar.models import Seminar +from webinar.models import Webinar # custom functions from functions.db import db_table_exists from functions.signal_handlers import post_save_handler -from functions.models_methods import ExpoManager +from functions.models_methods import ExpoManager, CityManager #check if table exist and create flags if true flags = [str(item.url) for item in Service.objects.all()] if db_table_exists('service_service') else [] @@ -28,11 +31,15 @@ class City(TranslatableModel): """ objects = ExpoManager() + used = CityManager() catalog = '/city/' services = BitField(flags=flags) url = models.SlugField(unique=True) + # + old_url = models.CharField(max_length=55) + inflect = models.CharField(max_length=255, blank=True) #relations country = models.ForeignKey('country.Country', null=True, on_delete=models.PROTECT, related_name='cities') code_IATA = models.ForeignKey(Iata, blank=True, null=True) @@ -56,6 +63,9 @@ class City(TranslatableModel): created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) + class Meta: + ordering = ['translations__name'] + def __unicode__(self): return self.lazy_translation_getter('name', self.pk) @@ -83,7 +93,19 @@ class City(TranslatableModel): def expositions_number(self): - return len(Exposition.objects.filter(city=self.id)) + return Exposition.objects.filter(city=self.id).count() + + def conferences_number(self): + + return Conference.objects.filter(city=self.id).count() + + def seminars_number(self): + + return Seminar.objects.filter(city=self.id).count() + + def webinars_number(self): + + return Webinar.objects.filter(city=self.id).count() def get_parent(self): parent = {'text' : self.country.name, 'id': self.country.id, 'name': 'co', diff --git a/company/edit_forms.py b/company/edit_forms.py index d7751b57..5d6ff973 100644 --- a/company/edit_forms.py +++ b/company/edit_forms.py @@ -4,6 +4,7 @@ from django.utils.translation import ugettext as _, get_language from country.models import Country from city.models import City from company.models import Company +from theme.models import Theme class BaseForm(forms.ModelForm): @@ -27,7 +28,7 @@ class NameForm(BaseForm): class SpecializationForm(BaseForm): translation = True - specialization = forms.CharField(label=_(u'Описание компании'), widget=forms.TextInput()) + specialization = forms.CharField(label=_(u'Описание компании'), widget=forms.TextInput(), required=False) class Meta: model = Company._meta.translations_model fields = ('specialization',) @@ -36,7 +37,7 @@ class SpecializationForm(BaseForm): class HomeForm(BaseForm): city = forms.CharField(label='Город', required=False, widget=forms.HiddenInput(attrs={'class': 'select2'})) - country = forms.ChoiceField(label=_(u'Страна'), choices=[(c.id, c.name) for c in Country.objects.all()], required=False, + country = forms.ChoiceField(label=_(u'Страна'), choices=[('', '')]+[(c.id, c.name) for c in list(Country.objects.all())], required=False, widget=forms.Select(attrs={'class': 'select2'})) def __init__(self, *args, **kwargs): super(HomeForm, self).__init__(*args, **kwargs) @@ -68,6 +69,19 @@ class PhoneForm(BaseForm): model = Company fields = ('phone',) + def clean_phone(self): + phone = self.cleaned_data['phone'] + if not phone: + return + + deduct = ('-','(',')','.',' ', '+') + for elem in deduct: + phone = phone.replace(elem, '') + if phone.isdigit(): + return phone + else: + raise forms.ValidationError(_(u'Введите правильный телефон')) + class EmailForm(BaseForm): email = forms.EmailField(label=_(u'Ваш e-mail'), required=False) @@ -94,12 +108,32 @@ class SocialForm(BaseForm): fields = ('facebook', 'twitter', 'vk', 'linkedin') +class ThemeForm(BaseForm): + theme = forms.ModelMultipleChoiceField(queryset=Theme.objects.all()) + class Meta: + model = Company + fields = ('theme',) + + class TagForm(BaseForm): tag = forms.CharField(required=False, widget=forms.HiddenInput(attrs={'class': 'select2'})) class Meta: model = Company fields = ('tag',) + def clean_tag(self): + tags = self.cleaned_data.get('tag') + if tags: + res = [] + for id in tags.split(','): + try: + res.append(int(id)) + except: + continue + return res + else: + return [] + class FoundationForm(BaseForm): class Meta: @@ -122,7 +156,7 @@ class DescriptionForm(BaseForm): class AddressForm(BaseForm): translation = True - address_inf = forms.CharField(label=_(u'Адрес компании'), widget=forms.TextInput()) + address_inf = forms.CharField(label=_(u'Адрес компании'), widget=forms.TextInput(), required=False) class Meta: model = Company._meta.translations_model fields = ('address_inf',) diff --git a/company/edit_views.py b/company/edit_views.py index 00ce6279..3e8e0921 100644 --- a/company/edit_views.py +++ b/company/edit_views.py @@ -1,13 +1,21 @@ import json -from django.http import HttpResponseRedirect, HttpResponse, Http404 +from django.http import HttpResponseRedirect, HttpResponse, Http404, HttpResponseForbidden from django.utils.translation import get_language from sorl.thumbnail import get_thumbnail from edit_forms import * from accounts.views import ProfileInvalidView +from .models import Company class BaseView(ProfileInvalidView): def form_valid(self, form): - company = self.request.user.company + slug = self.kwargs.get('slug') + if not slug: + raise Http404 + + company = Company.objects.get(url=slug) + if company.creator_id != self.request.user.id: + return HttpResponseForbidden() + if self.form_class.translation: lang = get_language() comp_transl = company.translations.get(language_code=lang) @@ -16,8 +24,12 @@ class BaseView(ProfileInvalidView): else: form = self.form_class(self.request.POST, instance=company) - form.save() - response = {'success': True} + company = form.save() + try: + rating = company.rating + except AttributeError: + rating = company.master.rating + response = {'success': True, 'rating': rating} return HttpResponse(json.dumps(response), content_type='application/json') @@ -30,12 +42,19 @@ class LogoView(BaseView): form_class = LogoForm def form_valid(self, form): - company = self.request.user.company + #company = self.request.user.company#!!! + + slug = self.kwargs.get('slug') + if not slug: + raise Http404 + company = Company.objects.get(url=slug) + if company.creator_id != self.request.user.id: + return HttpResponseForbidden() form = self.form_class(self.request.POST, self.request.FILES, instance=company) - form.save() + company = form.save() if self.request.is_ajax(): - im = get_thumbnail(company.logo, '100x100', crop='center') - response = {'success': True, 'url': im.url} + im = get_thumbnail(company.logo, '100x100', format="PNG") + response = {'success': True, 'url': im.url, 'rating': company.rating} return HttpResponse(json.dumps(response), content_type='application/json') else: return HttpResponseRedirect(company.get_permanent_url()) @@ -68,9 +87,56 @@ class SocialView(BaseView): form_class = SocialForm +class ThemeView(BaseView): + form_class = ThemeForm + + def form_valid(self, form): + slug = self.kwargs.get('slug') + if not slug: + raise Http404 + + company = Company.objects.get(url=slug) + if company.creator_id != self.request.user.id: + return HttpResponseForbidden() + + + form = self.form_class(self.request.POST, instance=company) + + company = form.save() + try: + rating = company.rating + except AttributeError: + rating = company.master.rating + themes = [{'text': item.name,'id': str(item.id),'url': '/members/theme/%s/'%item.url} for item in company.theme.all()] + response = {'success': True, 'rating': rating, 'tags': themes} + return HttpResponse(json.dumps(response), content_type='application/json') + + class TagView(BaseView): form_class = TagForm + def form_valid(self, form): + slug = self.kwargs.get('slug') + if not slug: + raise Http404 + + company = Company.objects.get(url=slug) + if company.creator_id != self.request.user.id: + return HttpResponseForbidden() + + + form = self.form_class(self.request.POST, instance=company) + + company = form.save() + try: + rating = company.rating + except AttributeError: + rating = company.master.rating + tags = [{'text': item.name,'id': str(item.id),'url': '/members/tag/%s/'%item.url} for item in company.tag.all()] + response = {'success': True, 'rating': rating, 'tags': tags} + return HttpResponse(json.dumps(response), content_type='application/json') + + class FoundationView(BaseView): form_class = FoundationForm diff --git a/company/forms.py b/company/forms.py index b50f12e5..ad2ff764 100644 --- a/company/forms.py +++ b/company/forms.py @@ -282,6 +282,8 @@ class CreateCompanyForm(forms.Form): def clean_url(self): url = self.cleaned_data['url'] + url = url.replace('http://expomap.ru/members/', '') + if not is_latin(url): raise forms.ValidationError(_(u'url должен состоять только из латинских букв')) diff --git a/company/models.py b/company/models.py index 69be58f3..4e98f85c 100644 --- a/company/models.py +++ b/company/models.py @@ -119,7 +119,7 @@ class Company(TranslatableModel, ExpoMixin): def calculate_rating(company): rating_simple = {'country': 5, 'city': 5, 'address_inf': 10, 'phone': 10, 'fax': 5, 'email': 10, - 'facebook': 5, 'twitter': 5, 'linkedin': 5, 'vk': 5, 'web_page': 10, #'logo': 20, + 'facebook': 5, 'twitter': 5, 'linkedin': 5, 'vk': 5, 'web_page': 10, 'logo': 20, 'specialization': 5, 'description':15, 'foundation': 5, 'staff_number': 5}# участие и посещение доделать rating_methods = {'theme': 10, 'tag': 5, 'photo':5} # base rating @@ -128,7 +128,13 @@ def calculate_rating(company): if getattr(company, key): rating += value + themes = company.theme.all().count() + rating += themes * 10 + tags = company.tag.all().count() + rating += tags * 10 if tags < 6 else 50 + company.rating = rating + # call to prevent recursion post_save.disconnect(create_company, sender=Company) company.save() @@ -139,4 +145,11 @@ def create_company(sender, instance, created, **kwargs): post_save_handler(sender, instance=instance, **kwargs) calculate_rating(instance) +def calculate_rating_for_translations(sender, instance, created, **kwargs): + company = instance.master + post_save.disconnect(calculate_rating_for_translations, sender=Company._meta.translations_model) + calculate_rating(company) + post_save.connect(calculate_rating_for_translations, sender=Company._meta.translations_model) + post_save.connect(create_company, sender=Company) +post_save.connect(calculate_rating_for_translations, sender=Company._meta.translations_model) diff --git a/company/search_indexes.py b/company/search_indexes.py index 1d197d9e..7a3f23fb 100644 --- a/company/search_indexes.py +++ b/company/search_indexes.py @@ -35,4 +35,7 @@ class CompanyExpositionIndex(indexes.SearchIndex, indexes.Indexable, ExpoSearchM def index_queryset(self, using=None): - return self.get_model().objects.filter() \ No newline at end of file + return self.get_model().objects.filter() + + def get_updated_field(self): + return 'modified' \ No newline at end of file diff --git a/company/urls.py b/company/urls.py index b1d47572..fefa6e3c 100644 --- a/company/urls.py +++ b/company/urls.py @@ -1,40 +1,42 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, url -from views import CompanyView, CompanySearchView, MemberDetail, MemberList, MemberTagList, MemberThemeList +from views import CompanySearchView, MemberDetail, MemberList, MemberTagList, MemberThemeList from django.contrib.auth.decorators import login_required from edit_views import * urlpatterns = patterns('', + url(r'company/create-company/$', 'company.views.create_company'), + url(r'company/get-company/$', 'company.views.get_company'), + # url(r'members/search/$', CompanySearchView.as_view()), #url(r'members/(?P.*)/(?P\d+)/$', CompanyView.as_view()), #url(r'members/(?P\d+)/$', CompanyView.as_view()), #url(r'members/(?P.*)/$', CompanyView.as_view()), #url(r'members/$', CompanyView.as_view()), - url(r'members/theme/(?P.*)/page/(?P\d+)/$', MemberThemeList.as_view()), - url(r'members/theme/(?P.*)/$', MemberThemeList.as_view()), - url(r'members/tag/(?P.*)/page/(?P\d+)/$', MemberTagList.as_view()), - url(r'members/tag/(?P.*)/$', MemberTagList.as_view()), - url(r'members/page/(?P\d+)/$', MemberList.as_view()), - url(r'members/(?P.*)/$', MemberDetail.as_view()), - url(r'members/$', MemberList.as_view()), + url(r'members/theme/(?P.*)/page/(?P\d+)/$', MemberThemeList.as_view(), {'meta_id':69}), + url(r'members/theme/(?P.*)/$', MemberThemeList.as_view(), {'meta_id':69}), + url(r'members/tag/(?P.*)/page/(?P\d+)/$', MemberTagList.as_view(), {'meta_id':70}), + url(r'members/tag/(?P.*)/$', MemberTagList.as_view(), {'meta_id':70}), + url(r'members/page/(?P\d+)/$', MemberList.as_view(), {'meta_id':67}), + url(r'members/(?P.*)/$', MemberDetail.as_view(), {'meta_id':68}), + url(r'members/$', MemberList.as_view(), {'meta_id':67}), # - url(r'company/create-company/$', 'company.views.create_company'), - url(r'company/get-company/$', 'company.views.get_company'), - # - url(r'company/update/name/$', login_required(NameView.as_view())), - url(r'^company/update/home/$', login_required(HomeView.as_view())), - url(r'^company/update/specialization/$', login_required(SpecializationView.as_view())), - url(r'^company/update/phone/$', login_required(PhoneView.as_view())), - url(r'^company/update/email/$', login_required(EmailView.as_view())), - url(r'^company/update/web-page/$', login_required(WebPageView.as_view())), - url(r'^company/update/social/$', login_required(SocialView.as_view())), - url(r'^company/update/tag/$', login_required(TagView.as_view())), - url(r'^company/update/foundation/$', login_required(FoundationView.as_view())), - url(r'^company/update/staff/$', login_required(StaffView.as_view())), - url(r'^company/update/description/$', login_required(DescriptionView.as_view())), - url(r'^company/update/address/$', login_required(AddressView.as_view())), - url(r'^company/update/logo/$', login_required(LogoView.as_view())), + url(r'company/update/name/(?P.*)/$', login_required(NameView.as_view())), + url(r'^company/update/home/(?P.*)/$', login_required(HomeView.as_view())), + url(r'^company/update/specialization/(?P.*)/$', login_required(SpecializationView.as_view())), + url(r'^company/update/phone/(?P.*)/$', login_required(PhoneView.as_view())), + url(r'^company/update/email/(?P.*)/$', login_required(EmailView.as_view())), + url(r'^company/update/web-page/(?P.*)/$', login_required(WebPageView.as_view())), + url(r'^company/update/social/(?P.*)/$', login_required(SocialView.as_view())), + url(r'^company/update/tag/(?P.*)/$', login_required(TagView.as_view())), + url(r'^company/update/theme/(?P.*)/$', login_required(ThemeView.as_view())), + url(r'^company/update/foundation/(?P.*)/$', login_required(FoundationView.as_view())), + url(r'^company/update/staff/(?P.*)/$', login_required(StaffView.as_view())), + url(r'^company/update/description/(?P.*)/$', login_required(DescriptionView.as_view())), + url(r'^company/update/address/(?P.*)/$', login_required(AddressView.as_view())), + url(r'^company/update/logo/(?P.*)/$', login_required(LogoView.as_view())), + ) diff --git a/company/views.py b/company/views.py index f3244d9f..80a04032 100644 --- a/company/views.py +++ b/company/views.py @@ -15,7 +15,8 @@ from .edit_forms import NameForm as CompNameForm, HomeForm as CompHomeForm, Phon EmailForm as CompEmailForm, WebPageForm as CompWebPageForm, SocialForm as CompSocialForm,\ TagForm as CompTagForm, DescriptionForm as CompDescr, StaffForm as CompStaff, \ FoundationForm as CompFound, SpecializationForm as CompSpec, AddressForm as CompAddress,\ - LogoForm as CompLogo + LogoForm as CompLogo, ThemeForm as CompThemeForm +from meta.views import MetadataMixin class CompanySearchView(ListView): @@ -51,7 +52,7 @@ class CompanySearchView(ListView): -class MemberList(ListView): +class MemberList(MetadataMixin, ListView): model = Company paginate_by = settings.CLIENT_PAGINATION template_name = 'client/company/companies_list.html' @@ -61,7 +62,7 @@ class MemberList(ListView): def get_queryset(self): return self.model.objects.order_by('-rating') -class MemberThemeList(ListView): +class MemberThemeList(MetadataMixin, ListView): model = Company paginate_by = settings.CLIENT_PAGINATION template_name = 'client/company/companies_list.html' @@ -72,11 +73,12 @@ class MemberThemeList(ListView): qs = super(MemberThemeList, self).get_queryset() slug = self.kwargs.get('slug') theme = get_object_or_404(Theme, url=slug) + self.kwargs['theme'] = theme qs = qs.filter(theme=theme) return qs -class MemberTagList(ListView): +class MemberTagList(MetadataMixin, ListView): model = Company paginate_by = settings.CLIENT_PAGINATION template_name = 'client/company/companies_list.html' @@ -87,13 +89,15 @@ class MemberTagList(ListView): qs = super(MemberTagList, self).get_queryset() slug = self.kwargs.get('slug') tag = get_object_or_404(Tag, url=slug) + self.kwargs['tag'] = tag qs = qs.filter(tag=tag) + return qs -class MemberDetail(DetailView): +class MemberDetail(MetadataMixin, DetailView): model = Company slug_field = 'url' template_name = 'client/company/company_detail.html' @@ -108,10 +112,21 @@ class MemberDetail(DetailView): forms = { 'home_form': CompHomeForm(instance=company), 'phone_form': CompPhoneForm(instance=company), 'email_form': CompEmailForm(instance=company), 'web_page_form': CompWebPageForm(instance=company), - 'social_form': CompSocialForm(instance=company), 'tag_form': CompTagForm(instance=company), + 'social_form': CompSocialForm(instance=company), 'staff_form': CompStaff(instance=company), 'found_form': CompFound(instance=company), 'logo_form': CompLogo(instance=company) } + tags = [{'id': str(tag.id), 'text': tag.name, 'url': '/members/tag/%s/'%tag.url} for tag in company.tag.all()] + tag_form = CompTagForm() + tag_form.fields['tag'].widget.attrs['data-predifined'] = json.dumps(tags) + tag_form.fields['tag'].widget.attrs['value'] = '' + + #themes = [{'id': str(item.id), 'text': item.name } for item in company.theme.all()] + theme_form = CompThemeForm(instance=company) + + #theme_form.fields['theme'].widget.attrs['data-predifined'] = json.dumps(themes) + #theme_form.fields['tag'].widget.attrs['value'] = '' + forms.update({'tag_form': tag_form, 'theme_form': theme_form}) lang = get_language() comp_transl = company.translations.get(language_code=lang) @@ -125,30 +140,6 @@ class MemberDetail(DetailView): return context -class CompanyView(ExpoListView): - paginate_by = 10 - model = Company - template_name = 'company_catalog.html' - search_form = CompanySearchForm - - def get_context_data(self, **kwargs): - context = super(CompanyView, self).get_context_data(**kwargs) - context['type'] = 'members search' - return context - -class CompanyExposition(CompanyView): - template_name = 'test_list.html' - - def get_queryset(self): - - params = self.get_params() - for param in params: - if param.get('type') == 'event': - company = Company.objects.safe_get(url=param.get('url')) - #query = exp.users - self.params = params - return company.exposition_companies.all() - def create_company(request): response = {'success': False} @@ -166,7 +157,7 @@ def get_company(request): if request.is_ajax(): term = request.GET['term'] qs = Company.objects.language().filter(translations__name__contains=term).distinct() - result = [{'id': company.id, 'label': company.name} for company in qs] + result = [{'id': company.id, 'label': company.name, 'logo': company.logo.url if company.logo else settings.NO_LOGO } for company in qs] return HttpResponse(json.dumps(result), content_type='application/json') else: return HttpResponse('not ajax') \ No newline at end of file diff --git a/conference/admin.py b/conference/admin.py index fa8a3790..d5d063b5 100644 --- a/conference/admin.py +++ b/conference/admin.py @@ -13,13 +13,14 @@ from forms import ConferenceChangeForm, ConferenceCreateForm, ConferenceDeleteFo from theme.models import Tag from city.models import City from file.models import FileModel, TmpFile -from file.forms import FileModelForm +from file.forms import FileModelForm, FileForm +from photologue.forms import PhotoForm #python import random #custom views from functions.custom_views import objects_list, delete_object from functions.views_help import get_referer -from functions.admin_views import AdminListView +from functions.admin_views import AdminListView, AdminView, upload_photo def conference_all(request): @@ -214,7 +215,84 @@ def conference_change(request, url): return render_to_response('conference_add.html', args) + +class ConferenceView(AdminView): + form_class = ConferenceCreateForm + model = Conference + success_url = '/admin/conference/all/' + template_name = 'admin/conference/conference.html' + + def form_valid(self, form): + self.set_obj() + expo = form.save(obj=self.obj) + + return HttpResponseRedirect(self.success_url) + + def get_form(self, form_class): + if self.request.POST: + return super(ConferenceView, self).get_form(form_class) + obj = self.set_obj() + if obj: + data = {'web_page':obj.web_page, 'foundation_year': obj.foundation_year, + 'data_begin':obj.data_begin, 'data_end':obj.data_end, 'currency':obj.currency, + 'tax':obj.tax, 'min_price':obj.min_price, 'max_price':obj.max_price, + '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], + 'quality_label': [item for item, bool in obj.quality_label if bool==True]} + + if obj.place: + data['place'] = obj.place.id + + data['theme'] = [item.id for item in obj.theme.all()] + data['tag'] = ','.join(['%s:%s'%(item.id, item.name) for item in obj.tag.all()]) + data['organiser'] = [item.id for item in obj.organiser.all()] + data['company'] = [item.id for item in obj.company.all()] + + data['country'] = obj.country_id + data['city'] = obj.city_id + + for code, name in settings.LANGUAGES: + trans_obj = self.model._meta.translations_model.objects.get(language_code = code,master__id=obj.id) #access to translated fields + data['name_%s' % code] = obj.name + data['description_%s' % code] = trans_obj.description + data['main_title_%s' % code] = trans_obj.main_title + data['time_%s' % code] = trans_obj.time + data['main_themes_%s' % code] = trans_obj.main_themes + data['discount_description_%s' % code] = trans_obj.discount_description + data['title_%s' % code] = trans_obj.title + data['keywords_%s' % code] = trans_obj.keywords + data['descriptions_%s' % code] = trans_obj.descriptions + + form =form_class(initial=data) + form.fields['city'].widget.attrs['data-init-text'] = obj.city.name + form.fields['tag'].choices = [(item.id, item.name) for item in Tag.objects.language().filter(theme__in=data['theme'])] + return form + else: + return form_class() + + + def get_context_data(self, **kwargs): + context = super(ConferenceView, self).get_context_data(**kwargs) + obj = self.set_obj() + if obj: + + context['stat_form'] = StatisticForm() + context['file_form'] = FileForm(initial={'model': 'conference.Conference'}) + files = FileModel.objects.filter(content_type=ContentType.objects.get_for_model(obj),object_id=getattr(obj, 'id')) + context['files'] = files + + context['photo_form'] = PhotoForm() + context['timetable_form'] = TimeTableForm() + context['timetables'] = TimeTable.objects.filter(conference=obj) + return context + + class ConferenceListView(AdminListView): template_name = 'admin/conference/conference_list.html' form_class = ConferenceFilterForm - model = Conference \ No newline at end of file + model = Conference + +def upload_conference_photo(request, conf_id): + return upload_photo(request, conf_id, Conference) \ No newline at end of file diff --git a/conference/admin_urls.py b/conference/admin_urls.py index b652b3f7..9a206a58 100644 --- a/conference/admin_urls.py +++ b/conference/admin_urls.py @@ -1,13 +1,15 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, include, url -from admin import ConferenceListView +from admin import ConferenceListView, ConferenceView urlpatterns = patterns('conference.admin', - url(r'^add.*/$', 'conference_add'), + url(r'^upload-photo/(?P.*)/$', 'upload_conference_photo'), url(r'^delete/(?P.*)$', 'conference_delete'), - url(r'^change/(?P.*)/$', 'conference_change'), - url(r'^copy/(?P.*)/$', 'conference_copy'), - url(r'^switch/(?P.*)/(?P.*)$', 'conference_switch'), - #url(r'^all/$', 'conference_all'), url(r'^all/$', ConferenceListView.as_view()), + #url(r'^change/(?P.*)/$', 'conference_change'), + + url(r'^switch/(?P.*)/(?P.*)$', 'conference_switch'), + + url(r'^(?P.*)/$', ConferenceView.as_view()), + url(r'^$', ConferenceView.as_view()), ) \ No newline at end of file diff --git a/conference/forms.py b/conference/forms.py index a70a3418..cf3fa4cd 100644 --- a/conference/forms.py +++ b/conference/forms.py @@ -5,10 +5,10 @@ from ckeditor.widgets import CKEditorWidget from django.forms.util import ErrorList from django.core.validators import validate_email, URLValidator #models -from models import Conference, TimeTable, CURRENCY, Statistic +from models import Conference, TimeTable, CURRENCY, Statistic, BIT_AUDIENCE from country.models import Country from city.models import City -from theme.models import Theme +from theme.models import Theme, Tag from organiser.models import Organiser from accounts.models import User from company.models import Company @@ -21,6 +21,9 @@ from functions.files import check_tmp_files from functions.form_check import translit_with_separator from functions.admin_forms import AdminFilterForm +places = [(item.id, item.name) for item in PlaceConference.objects.language().all()] +places.insert(0,('', 'Не выбрано')) + class ConferenceCreateForm(forms.Form): """ @@ -31,18 +34,35 @@ class ConferenceCreateForm(forms.Form): save function saves data in Conference object. If it doesnt exist create new object """ + PERIODIC = ((0, u'Не выбрано'), + (1.0, u'Ежегодно'), (2.0, u'2 раза в год'), (3.0, u'3 раза в год'), + (4.0, u'4 раза в год'), (5.0, u'5 раз в год'), + (0.5, u'Раз в 2 года'),(0.33, u'Раз в 3 года'),(0.25, u'Раз в 4 года')) + + public = [(item1, item2) for item1, item2 in BIT_AUDIENCE] + currencies = [(item, item) for item in CURRENCY] - data_begin = forms.DateField(label='Дата начала') - data_end = forms.DateField(label='Дата окночания') + data_begin = forms.DateField(label=u'Дата начала', input_formats=['%Y-%m-%d', '%d.%m.%Y']) + 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()]) + + 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()]) + + place = forms.ChoiceField(label=u'Место проведения', required=False, + choices=places) - country = forms.ModelChoiceField(label='Страна', queryset=Country.objects.all(), empty_label=None) - theme = forms.ModelMultipleChoiceField(label='Тематики', queryset=Theme.objects.all()) - place = forms.ModelChoiceField(label='Место проведения', queryset=PlaceConference.objects.all(), - empty_label='', required=False) #creates select input with empty choices cause it will be filled with ajax - city = forms.ChoiceField(label='Город', choices=[('','')]) - tag = forms.MultipleChoiceField(label='Теги', required=False) + city = forms.CharField(label=u'Город', widget=forms.HiddenInput()) + tag = forms.CharField(label=u'Теги', widget=forms.HiddenInput(), required=False) + + periodic = forms.ChoiceField(label=u'Периодичность', choices=PERIODIC, required=False) + audience = forms.MultipleChoiceField(label=u'Аудитория', choices=public, initial='', required=False) web_page = forms.CharField(label='Веб страница', required=False) link = forms.CharField(label='Линк на регистрацию', required=False) @@ -61,9 +81,7 @@ class ConferenceCreateForm(forms.Form): quality_label = forms.MultipleChoiceField(label='Тип', required=False, choices=[('ufi', 'UFI'), ('rsva', 'РСВЯ'), ('exporating', 'ExpoRating')], widget=forms.CheckboxSelectMultiple()) - #field for comparing tmp files - key = forms.CharField(required=False, widget=forms.HiddenInput()) - # + conference_id = forms.CharField(required=False, widget=forms.HiddenInput()) @@ -99,14 +117,8 @@ class ConferenceCreateForm(forms.Form): widget=forms.TextInput(attrs={'style':'width: 550px'})) - #!service has bitfield. uncomment when country data will be filled - #services = [(item.id, item.name) for item in Service.objects.all()] - #self.fields['service'] = forms.ChoiceField(label='Услуги', choices=services, required=False) - - - - def save(self, id=None): + def save(self, obj=None): """ changes Conference model object with id = id N/A add new Conference model object @@ -115,15 +127,18 @@ class ConferenceCreateForm(forms.Form): """ data = self.cleaned_data #create new conference object or get exists - if not id: + if not obj: conference = Conference() else: - conference = Conference.objects.get(id=id) + conference = obj conference.theme.clear() conference.tag.clear() #simple fields conference.url = translit_with_separator(data['name_ru'].strip()).lower() + if data.get('logo'): + conference.logo = data['logo'] + conference.data_begin = data['data_begin'] conference.data_end = data['data_end'] conference.link = data['link'] @@ -141,6 +156,7 @@ class ConferenceCreateForm(forms.Form): conference.expohit = data['expohit'] conference.canceled = data['canceled'] conference.moved = data['moved'] + conference.periodic = data['periodic'] # generates bitfield flag = 0 if data['quality_label']: @@ -148,32 +164,36 @@ class ConferenceCreateForm(forms.Form): conference.quality_label = flag + audience = 0 + if data['audience']: + audience = reduce(lambda x,y: x|y, (getattr(Conference.audience, item) for item in data['audience'])) + + conference.audience = audience + if data.get('country'): - conference.country = Country.objects.get(id=data['country'].id)#.id cause select uses queryset + conference.country = Country.objects.get(id=data['country'])#.id cause select uses queryset if data.get('city'): conference.city = City.objects.get(id=data['city']) if data.get('place'): - conference.place = PlaceConference.objects.get(id=data['place'].id)#.id cause select uses queryset + conference.place = PlaceConference.objects.get(id=data['place']) + else: + conference.place = None # fill translated fields and save object fill_with_signal(Conference, conference, data) - #fill manytomany fields - for item in data['theme']: - conference.theme.add(item.id)#.id cause select uses queryset + conference.theme.add(*data['theme']) + conference.tag.add(*Tag.objects.filter(id__in=data['tag'])) + conference.organiser.add(*Organiser.objects.filter(id__in=data.get('organiser', []))) + - for item in data['tag']: - conference.tag.add(item) - # uses because in the next loop data will be overwritten conference.save() - #save files - check_tmp_files(conference, data['key']) return conference - + """ def clean(self): id = self.cleaned_data.get('conference_id') name_ru = self.cleaned_data.get('name_ru') @@ -185,6 +205,20 @@ class ConferenceCreateForm(forms.Form): del self.cleaned_data['name_ru'] return self.cleaned_data + """ + + def clean_tag(self): + tags = self.cleaned_data.get('tag') + if tags: + res = [] + for id in tags.split(','): + try: + res.append(int(id)) + except: + continue + return res + else: + return [] def clean_web_page(self): """ diff --git a/conference/models.py b/conference/models.py index 52221bd3..4ba66129 100644 --- a/conference/models.py +++ b/conference/models.py @@ -1,8 +1,13 @@ # -*- coding: utf-8 -*- +from django.utils.translation import ugettext as _ 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 exposition.manager import ClientManager from hvad.models import TranslatableModel, TranslatedFields, TranslationManager +from functions.translate import fill_with_signal +from photologue.models import Gallery from functions.signal_handlers import post_save_handler, pre_save_handler import copy from bitfield import BitField @@ -12,11 +17,14 @@ from functions.db import db_table_exists from functions.custom_fields import EnumField from functions.models_methods import ExpoManager from functions.model_mixin import EventMixin, ExpoMixin +from functions.models_methods import hvad_to_dict # check if table exist and create flags if true -flags = [str(item.id) for item in Service.objects.all()] if db_table_exists('service_service') else [] +flags = [item.url for item in Service.objects.all()] if db_table_exists('service_service') else [] +from django.conf import settings -CURRENCY = ('RUB', 'USD', 'EUR') +CURRENCY = settings.CURRENCY +BIT_AUDIENCE = settings.BIT_AUDIENCE class Conference(TranslatableModel, EventMixin, ExpoMixin): """ @@ -25,17 +33,23 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin): Uses hvad.TranslatableModel which is child of django.db.models class """ catalog = '/conference/' + catalog_name = _(u'Конференции:') # type of event event_type = 'conf' #set manager of this model objects = ExpoManager() + enable = ClientManager() - url = models.SlugField(unique=True) + url = models.SlugField(unique=True, max_length=255) + old_url = models.SlugField(unique=True, max_length=255) data_begin = models.DateField(verbose_name='Дата начала') data_end = models.DateField(verbose_name='Дата окончания') + services = BitField(flags=flags) #relations - country = models.ForeignKey('country.Country', verbose_name='Страна', on_delete=models.PROTECT) - city = models.ForeignKey('city.City', verbose_name='Город', on_delete=models.PROTECT) + country = models.ForeignKey('country.Country', verbose_name='Страна', on_delete=models.PROTECT, + related_name='conference_country') + city = models.ForeignKey('city.City', verbose_name='Город', on_delete=models.PROTECT, + related_name='conference_city') place = models.ForeignKey('place_conference.PlaceConference', verbose_name='Место проведения', blank=True, null=True, on_delete=models.PROTECT, related_name='conference_place') theme = models.ManyToManyField('theme.Theme', verbose_name='Тематики', @@ -48,15 +62,20 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin): blank=True, null=True, related_name='conference_companies') users = models.ManyToManyField('accounts.User', verbose_name='Посетители выставки', blank=True, null=True, related_name='conference_users') - #!service has bitfield uncomment when country data will be filled - services = BitField(flags=flags) - #service = models.ManyToManyField('service.Service', verbose_name='Услуги', blank=True, null=True) + photogallery = models.ForeignKey('photologue.Gallery', blank=True, null=True) + logo = models.ImageField(verbose_name='Logo', upload_to='conference/logo/', blank=True) + rating = models.IntegerField(default=0, db_index=True) # добавить индекс в базе + + quality_label = BitField(flags=['ufi', 'rsva', 'exporating']) + + periodic = models.FloatField(verbose_name='Переодичность', blank=True, null=True) + audience = BitField(flags=[k for k, v in BIT_AUDIENCE]) web_page = models.CharField(verbose_name='Вебсайт', max_length=255, blank=True) link = models.CharField(verbose_name='Линк на регистрацию', max_length=255, blank=True) - quality_label = BitField(flags=['ufi', 'rsva', 'exporating']) discount = models.PositiveIntegerField(verbose_name='Скидка', blank=True, null=True) # - currency = EnumField(values=CURRENCY, default='RUB') + + currency = EnumField(values=CURRENCY, default='USD') tax = models.BooleanField(verbose_name='Налог', default=1) min_price = models.PositiveIntegerField(verbose_name='Минимальная цена', blank=True, null=True) max_price = models.PositiveIntegerField(verbose_name='Максимальная цена', blank=True, null=True) @@ -69,6 +88,7 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin): is_published = models.BooleanField(default=0) files = generic.GenericRelation('file.FileModel', content_type_field='content_type', object_id_field='object_id') + note = generic.GenericRelation('note.Note', content_type_field='content_type', object_id_field='object_id') # statistic foundation_year = models.PositiveIntegerField(verbose_name='Год основания', blank=True, null=True) visitors = models.PositiveIntegerField(verbose_name='Посетитеил', blank=True, null=True) @@ -98,54 +118,33 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin): def __unicode__(self): return self.lazy_translation_getter('name', unicode(self.pk)) + def get_services(self): + + country_ids = [item for item, bool in self.country.services if bool==True] + ids = [item for item, bool in self.services if bool==True] + + qs = Service.objects.filter(Q(Q(url__in=country_ids) & Q(type=Service.type.conference)) | Q(url__in=ids)) + + return list(qs) + #return list(Service.objects.language().filter(url__in=ids, type=Service.type.conference).order_by('sort')) + def get_nearest_events(self): conferences = Conference.objects.all()[:5] return conferences def get_catalog_url(self): - return '/conferences/' - - def clone(self): - """ - Return an identical copy of the instance with a new ID. - """ - if not self.pk: - raise ValueError('Instance must be saved before it can be cloned.') - - duplicate = copy.copy(self) - # Setting pk to None. Django thinking this is a new object. - duplicate.pk = None - # url must be unique - duplicate.url += '_copy' - if Conference.objects.safe_get(url=duplicate.url): - #already has copy this instance - return - - # duplicate should not be published - duplicate.is_published = False - duplicate.cancel_by_administrator = False - - 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.save() - # but lost all ManyToMany relations and Translations. - - # 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 + return '/conference/' + + def get_audience(self): + checked = [item for item, bool in self.audience if bool==True] + audience = [] + for k, v in BIT_AUDIENCE: + for item in checked: + if item == k: + audience.append(v) + + return ', '.join(audience) + def get_calendar_url(self): return '/conference-add-calendar/%s/'%self.id @@ -153,12 +152,51 @@ class Conference(TranslatableModel, EventMixin, ExpoMixin): def get_visit_url(self): return '/conference-visit/%s/'%self.id + def get_note_by_user(self, user_id): + note = self.note.filter(user__id=user_id) + try: + return note.get().text + except: + return '' + + def tags(self): + return self.tag.language().all() + + def get_gallery(self): + if self.photogallery: + return self.photogallery -class Statistic(models.Model): + data = {} + model = type(self) + for code, name in settings.LANGUAGES: + obj = model._meta.translations_model.objects.get(language_code = code,master__id=self.id) #access to translated fields + data['title_%s'%code] = obj.name + data['description_%s'%code] = obj.description + + gallery = Gallery() + + fill_with_signal(Gallery, gallery, data) + self.photogallery = gallery + self.save() + + + return gallery + + +class Statistic(TranslatableModel): conference = models.ForeignKey(Conference, related_name='statistic') year = models.PositiveIntegerField(verbose_name='Год') - members = models.PositiveIntegerField(verbose_name='Посетители') - visitors = models.PositiveIntegerField(verbose_name='Участники') + members = models.PositiveIntegerField(verbose_name='Посетители', blank=True, null=True) + visitors = models.PositiveIntegerField(verbose_name='Участники', blank=True, null=True) + area = models.PositiveIntegerField(verbose_name='Площадь', blank=True, null=True) + countries_number = models.PositiveIntegerField(verbose_name='Количество стран', blank=True, null=True) + + translations = TranslatedFields( + countries = models.TextField(blank=True) + ) + + def to_dict(self): + return hvad_to_dict(self) class TimeTable(TranslatableModel): @@ -166,13 +204,27 @@ class TimeTable(TranslatableModel): TimeTable for business program """ - exposition = models.ForeignKey(Conference, related_name='business_program') + conference = models.ForeignKey(Conference, related_name='business_program') begin = models.DateTimeField(verbose_name='Начало') end = models.DateTimeField(verbose_name='Конец') + timetable_organiser = models.ForeignKey('organiser.Organiser', null=True, blank=True, + related_name='conf_timetable') + # + created = models.DateTimeField(auto_now_add=True) + modified = models.DateTimeField(auto_now=True) #translated fields translations = TranslatedFields( - name = models.CharField(verbose_name='Название', max_length=255) + name = models.CharField(verbose_name='Название программы', max_length=255, blank=True), + programe = models.TextField(verbose_name='Программа'), + speaker = models.CharField(verbose_name='Спикеры', max_length=255, blank=True), + place = models.CharField(verbose_name='Место проведения', max_length=255, blank=True) ) + def to_dict(self): + return hvad_to_dict(self) + + pre_save.connect(pre_save_handler, sender=Conference) -post_save.connect(post_save_handler, sender=Conference) \ No newline at end of file +post_save.connect(post_save_handler, sender=Conference) +post_save.connect(post_save_handler, sender=TimeTable) +post_save.connect(post_save_handler, sender=Statistic) \ No newline at end of file diff --git a/conference/search_indexes.py b/conference/search_indexes.py index 64929dca..3266fb52 100644 --- a/conference/search_indexes.py +++ b/conference/search_indexes.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from haystack import indexes from models import Conference @@ -5,6 +6,32 @@ from models import Conference class ConferenceIndex(indexes.SearchIndex, indexes.Indexable): text = indexes.CharField(document=True, use_template=True) where = indexes.MultiValueField() + url = indexes.CharField() + data_begin = indexes.DateField(model_attr='data_begin') + data_end = indexes.DateField(model_attr='data_end') + theme = indexes.MultiValueField() + tag = indexes.MultiValueField() + country_id = indexes.IntegerField() + city_id = indexes.IntegerField() + area_id = indexes.IntegerField() + 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 None + + def prepare_catalog_name_en(self, obj): + return u'Conferences' + + 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()] @@ -18,3 +45,5 @@ class ConferenceIndex(indexes.SearchIndex, indexes.Indexable): return self.get_model().objects.filter(is_published=True) + def get_updated_field(self): + return "modified" diff --git a/conference/urls.py b/conference/urls.py index f4cc71b7..29f29e3b 100644 --- a/conference/urls.py +++ b/conference/urls.py @@ -1,15 +1,74 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, include, url -from views import ConferenceView +from views import ConferenceDetail, ConferenceList, ConferenceByCity, ConferenceByCountry, ConferenceByTheme,\ + ConferenceCountryCatalog, ConferenceCityCatalog, ConferenceTagCatalog, ConferenceThemeCatalog, ConferenceMembers,\ + ConferenceVisitors, ConferenceServiceView +from exposition.views import ExpositionSearchView urlpatterns = patterns('', - url(r'conferences/(?P.*)/(?P\d+)/$', ConferenceView.as_view()), - url(r'conferences/(?P\d+)/$', ConferenceView.as_view()), - url(r'conferences/(?P.*)/$', ConferenceView.as_view()), - url(r'conferences/$', ConferenceView.as_view()), - # + + + url(r'conference/add-note/(?P.*)/$', 'conference.views.add_note'), url(r'conference-add-calendar/(?P\d+)/$', 'conference.views.conference_add_calendar'), - url(r'conference-remove-calendar/(?P\d+)/$', 'conference.views.conference_remove_calendar'), url(r'conference-visit/(?P\d+)/$', 'conference.views.conference_visit'), - url(r'conference-unvisit/(?P\d+)/$', 'conference.views.conference_unvisit'), + # search + url(r'conference/search/', ExpositionSearchView.as_view()), + # country catalog + url(r'conference/country/$', ConferenceByCountry.as_view(), {'meta_id':51}), + url(r'conference/country/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', ConferenceCountryCatalog.as_view(), {'meta_id':25}), + url(r'conference/country/(?P.*)/(?P\d+)/page/(?P\d+)/$', ConferenceCountryCatalog.as_view(), {'meta_id':24}), + url(r'conference/country/(?P.*)/page/(?P\d+)/$', ConferenceCountryCatalog.as_view(), {'meta_id':23}), + url(r'conference/country/(?P.*)/(?P\d+)/(?P.*)/$', ConferenceCountryCatalog.as_view(), {'meta_id':25}), + url(r'conference/country/(?P.*)/(?P\d+)/$', ConferenceCountryCatalog.as_view(), {'meta_id':24}), + url(r'conference/country/(?P.*)/$', ConferenceCountryCatalog.as_view(), {'meta_id':23}), + # city catalog + url(r'conference/city/$', ConferenceByCity.as_view(), {'meta_id':52}), + url(r'conference/city/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', ConferenceCityCatalog.as_view(), {'meta_id':28}), + url(r'conference/city/(?P.*)/(?P\d+)/page/(?P\d+)/$', ConferenceCityCatalog.as_view(), {'meta_id':27}), + url(r'conference/city/(?P.*)/page/(?P\d+)/$', ConferenceCityCatalog.as_view(), {'meta_id':26}), + url(r'conference/city/(?P.*)/(?P\d+)/(?P.*)/$', ConferenceCityCatalog.as_view(), {'meta_id':28}), + url(r'conference/city/(?P.*)/(?P\d+)/$', ConferenceCityCatalog.as_view(), {'meta_id':27}), + url(r'conference/city/(?P.*)/$', ConferenceCityCatalog.as_view(), {'meta_id':26}), + # theme catalog + url(r'conference/theme/$', ConferenceByTheme.as_view(), {'meta_id':50}), + url(r'conference/theme/(?P.*)/country/(?P.*)/page/(?P\d+)/$', ConferenceThemeCatalog.as_view()), + url(r'conference/theme/(?P.*)/country/(?P.*)/$', ConferenceThemeCatalog.as_view()), + url(r'conference/theme/(?P.*)/city/(?P.*)/page/(?P\d+)/$', ConferenceThemeCatalog.as_view()), + url(r'conference/theme/(?P.*)/city/(?P.*)/$', ConferenceThemeCatalog.as_view()), + url(r'conference/theme/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', ConferenceThemeCatalog.as_view(), {'meta_id':31}), + url(r'conference/theme/(?P.*)/(?P\d+)/page/(?P\d+)/$', ConferenceThemeCatalog.as_view(), {'meta_id':30}), + url(r'conference/theme/(?P.*)/page/(?P\d+)/$', ConferenceThemeCatalog.as_view(), {'meta_id':29}), + url(r'conference/theme/(?P.*)/(?P\d+)/(?P.*)/$', ConferenceThemeCatalog.as_view(), {'meta_id':31}), + url(r'conference/theme/(?P.*)/(?P\d+)/$', ConferenceThemeCatalog.as_view(), {'meta_id':30}), + url(r'conference/theme/(?P.*)/$', ConferenceThemeCatalog.as_view(), {'meta_id':29}), + # tag catalog + url(r'conference/tag/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', ConferenceTagCatalog.as_view(), {'meta_id':34}), + url(r'conference/tag/(?P.*)/(?P\d+)/page/(?P\d+)/$', ConferenceTagCatalog.as_view(), {'meta_id':33}), + url(r'conference/tag/(?P.*)/page/(?P\d+)/$', ConferenceTagCatalog.as_view(), {'meta_id':32}), + url(r'conference/tag/(?P.*)/(?P\d+)/(?P.*)/$', ConferenceTagCatalog.as_view(), {'meta_id':34}), + url(r'conference/tag/(?P.*)/(?P\d+)/$', ConferenceTagCatalog.as_view(), {'meta_id':33}), + url(r'conference/tag/(?P.*)/$', ConferenceTagCatalog.as_view(), {'meta_id':32}), + # conf additional pages + url(r'conference/(?P.*)/visitors/page/(?P\d+)/$', ConferenceVisitors.as_view()), + url(r'conference/(?P.*)/visitors/$', ConferenceVisitors.as_view()), + url(r'conference/(?P.*)/members/page/(?P\d+)/$', ConferenceMembers.as_view()), + url(r'conference/(?P.*)/members/$', ConferenceMembers.as_view()), + url(r'conference/(?P.*)/service/(?P.*)/', ConferenceServiceView.as_view()), + + # conf list + url(r'conference/(?P\d+)/(?P.*)/page/(?P\d+)/$', ConferenceList.as_view(), {'meta_id':22}), + url(r'conference/(?P\d+)/page/(?P\d+)/$', ConferenceList.as_view(), {'meta_id':21}), + url(r'conference/(?P\d+)/(?P.*)/$', ConferenceList.as_view(), {'meta_id':22}), + url(r'conference/(?P\d+)/$', ConferenceList.as_view(), {'meta_id':21}), + url(r'conference/page/(?P\d+)/$', ConferenceList.as_view(), {'meta_id':20}), + # conf page + url(r'conference/(?P.*)/$', ConferenceDetail.as_view(), {'meta_id':35}), + url(r'conference/$', ConferenceList.as_view(), {'meta_id':20}), + ) + + +""" + + +""" \ No newline at end of file diff --git a/conference/views.py b/conference/views.py index 7b146288..71ec8f9d 100644 --- a/conference/views.py +++ b/conference/views.py @@ -1,12 +1,387 @@ # -*- coding: utf-8 -*- -from django.http import HttpResponse -from models import Conference -from functions.custom_views import ExpoListView import json +import datetime +from django.conf import settings +from django.http import HttpResponse, Http404, HttpResponseRedirect +from django.contrib import messages +from django.shortcuts import get_object_or_404 +from django.contrib.contenttypes.models import ContentType +from django.views.generic import ListView, DetailView +from django.views.generic.edit import FormMixin +from django.utils.translation import ugettext as _ +from django.utils import translation +from note.models import Note +from models import Conference +from accounts.models import User +from country.models import Country +from city.models import City +from theme.models import Theme, Tag +from service.order_forms import AdvertiseForm +from functions.search_forms import ExpositionSearchForm +from meta.views import MetadataMixin +from functions.cache_mixin import JitterCacheMixin, CacheMixin + +MONTHES = settings.MONTHES + + +class ConferenceBy(JitterCacheMixin, MetadataMixin, ListView): + cache_range = settings.CACHE_RANGE + template_name = 'conference/conference_by.html' + title1 = '' + title2 = '' + + """ + abstact class + """ + def get_context_data(self, **kwargs): + context = super(ConferenceBy, self).get_context_data(**kwargs) + context.update({'title1': self.title1, 'title2': self.title2, 'catalog': self.catalog}) + + return context + + +class ConferenceByCountry(ConferenceBy): + model = Country + title1 = _(u'По странам') + title2 = _(u'Коференции мира по странам') + catalog = 'country/' + + def get_queryset(self): + return self.model.objects.conference_countries_with_count() + #lang = translation.get_language() + #return self.model.objects.select_related('conference_country')\ + # .filter(conference_country__country__isnull=False, translations__language_code=lang)\ + # .order_by('translations__name').distinct() + + +class ConferenceByTheme(ConferenceBy): + model = Theme + title1 = _(u'По тематикам') + title2 = _(u'Коференции мира по тематикам') + catalog = 'theme/' + + def get_queryset(self): + return self.model.active.conference_themes_with_count() + #lang = translation.get_language() + #return self.model.objects.select_related('conference_themes')\ + # .filter(conference_themes__theme__isnull=False, translations__language_code=lang)\ + # .order_by('translations__name').distinct() + + +class ConferenceByCity(ConferenceBy): + model = City + title1 = _(u'По городам') + title2 = _(u'Коференции мира по городам') + catalog = 'city/' + + def get_queryset(self): + return self.model.used.conference_cities_with_count() + #lang = translation.get_language() + #return self.model.objects.select_related('conference_city')\ + # .filter(conference_city__city__isnull=False, translations__language_code=lang)\ + # .order_by('translations__name').distinct() + + +class ConferenceCatalog(JitterCacheMixin, MetadataMixin, ListView): + cache_range = settings.CACHE_RANGE + model = Conference + paginate_by = settings.CLIENT_PAGINATION + template_name = 'client/conference/catalog.html' + search_form = ExpositionSearchForm + filter_object = None + year = None + month = None + country = None + city = None + + def get_filtered_qs(self): + # diferent for views + pass + + def get_queryset(self): + qs = self.get_filtered_qs() + + year = self.kwargs.get('year') + if year: + qs = self.model.enable.filter(data_end__year=year) + filter_object = self.filter_object + if isinstance(filter_object, Country): + qs = qs.filter(country=filter_object) + elif isinstance(filter_object, City): + qs = qs.filter(city=filter_object) + elif isinstance(filter_object, Theme): + qs = qs.filter(theme=filter_object) + if self.kwargs.get('country'): + qs = qs.filter(country=self.kwargs.get('country')) + if self.kwargs.get('city'): + qs = qs.filter(city=self.kwargs.get('city')) + elif isinstance(filter_object, Tag): + qs = qs.filter(tag=filter_object) + + # info for breadscrumbs + self.year = {'text': year, 'link': '%s%s/%s/'%(self.catalog_url, self.filter_object.url, year)} + + + month = self.kwargs.get('month') + monthes = {'jan': {'value': 1, 'name': _(u'Январь')}, 'feb': {'value': 2, 'name': _(u'Февраль')}, + 'mar': {'value': 3, 'name': _(u'Март')}, 'apr': {'value': 4, 'name': _(u'Апрель')}, + 'may': {'value': 5, 'name': _(u'Май')}, 'jun': {'value': 6, 'name': _(u'Июнь')}, + 'jul': {'value': 7, 'name': _(u'Июль')}, 'aug': {'value': 8, 'name': _(u'Август')}, + 'sep': {'value': 9, 'name': _(u'Сентябрь')}, 'oct': {'value': 10, 'name': _(u'Октябрь')}, + 'nov': {'value': 11, 'name': _(u'Ноябрь')}, 'dec': {'value': 12, 'name': _(u'Декабрь')}} + if month and monthes.get(month): + qs = qs.filter(data_begin__month=monthes[month]['value']) + if self.country: + self.month = {'text': monthes[month]['name'], 'link': '%s%s/country/%s/%s/%s/'% + (self.catalog_url, self.filter_object.url, self.country.url, year, month)} + elif self.city: + self.month = {'text': monthes[month]['name'], 'link': '%s%s/city/%s/%s/%s/'% + (self.catalog_url, self.filter_object.url, self.city.url, year, month)} + else: + self.month = {'text': monthes[month]['name'], 'link': '%s%s/%s/%s/'%(self.catalog_url, self.filter_object.url, year, month)} + + return qs.order_by('data_begin') + + + def get_context_data(self, **kwargs): + context = super(ConferenceCatalog, self).get_context_data(**kwargs) + context['search_form'] = self.search_form + context['filter_object'] = self.filter_object + context['year'] = self.year + context['month'] = self.month + context['catalog_url'] = self.catalog_url + return context + +class ConferenceCountryCatalog(ConferenceCatalog): + catalog_url = '/conference/country/' + def get_filtered_qs(self): + #this method used in parent get_queryset + slug = self.kwargs.get('slug') + country = get_object_or_404(Country, url=slug) + self.kwargs['country'] = country + self.filter_object = country + qs = self.model.enable.upcoming().filter(country=country) + return qs + +class ConferenceCityCatalog(ConferenceCatalog): + catalog_url = '/conference/city/' + def get_filtered_qs(self): + #this method used in parent get_queryset + slug = self.kwargs.get('slug') + city = get_object_or_404(City, url=slug) + self.kwargs['city'] = city + qs = self.model.enable.upcoming().filter(city=city) + self.filter_object = city + return qs + + +class ConferenceThemeCatalog(ConferenceCatalog): + template_name = 'conference/catalog_theme.html' + catalog_url = '/conference/theme/' + country = None + city = None + + def get_filtered_qs(self): + #this method used in parent get_queryset + slug = self.kwargs.get('slug') + country_slug = self.kwargs.get('country_slug') + city_slug = self.kwargs.get('city_slug') + theme = get_object_or_404(Theme, url=slug) + self.kwargs['theme'] = theme + + qs = self.model.enable.upcoming().filter(theme=theme) + if country_slug: + country = get_object_or_404(Country, url=country_slug) + self.country = country + qs = qs.filter(country=country) + + if city_slug: + city = get_object_or_404(City, url=city_slug) + self.city = city + qs = qs.filter(city=city) + + self.filter_object = theme + return qs + + def get_context_data(self, **kwargs): + context = super(ConferenceThemeCatalog, self).get_context_data(**kwargs) + if self.country: + context['country'] = self.country + if self.city: + context['city'] = self.city + return context + + +class ConferenceTagCatalog(ConferenceCatalog): + catalog_url = '/conference/tag/' + def get_filtered_qs(self): + #this method used in parent get_queryset + slug = self.kwargs.get('slug') + tag = get_object_or_404(Tag, url=slug) + self.kwargs['tag'] = tag + qs = self.model.enable.upcoming().filter(tag=tag) + self.filter_object = tag + return qs + + +class ConferenceVisitors(MetadataMixin, ListView): + paginate_by = settings.CLIENT_PAGINATION + model = Conference + #template_name = 'event_visitors.html' + + template_name = 'client/conference/visitors.html' + + obj = None + search_form = ExpositionSearchForm + + def get_queryset(self): + slug = self.kwargs.get('slug') + conference = get_object_or_404(self.model, url=slug) + self.obj = conference + return conference.users.all() + + def get_context_data(self, **kwargs): + context = super(ConferenceVisitors, self).get_context_data(**kwargs) + context['object'] = self.obj + context['search_form'] = self.search_form + return context + + +class ConferenceMembers(MetadataMixin, ListView): + paginate_by = settings.CLIENT_PAGINATION + model = Conference + #template_name = 'event_visitors.html' + + template_name = 'client/conference/members.html' + + obj = None + search_form = ExpositionSearchForm + + def get_queryset(self): + slug = self.kwargs.get('slug') + conference = get_object_or_404(self.model, url=slug) + self.obj = conference + return conference.company.all() + + def get_context_data(self, **kwargs): + context = super(ConferenceMembers, self).get_context_data(**kwargs) + context['object'] = self.obj + context['search_form'] = self.search_form + return context + +from service.models import Service +from service.views import order_forms +class ConferenceServiceView(FormMixin, DetailView): + model = Conference + slug_field = 'url' + service = None + success_url = '/service/thanks/' + + def post(self, request, *args, **kwargs): + self.object = self.get_object() + service_url = self.kwargs.get('service_url') + service = get_object_or_404(Service, url=service_url) + service_form = order_forms.get(service_url) + self.form_class = service_form + form = self.get_form(service_form) + + if form.is_valid(): + return self.form_valid(form) + else: + return self.form_invalid(form) + + def get_context_data(self, **kwargs): + context = super(ConferenceServiceView, self).get_context_data(**kwargs) + service_url = self.kwargs.get('service_url') + service = get_object_or_404(Service, url=service_url) + self.service = service + self.template_name = service.template + form = order_forms.get(service_url) + self.form_class = form + if not form: + raise Http404 + context['form'] = self.get_form(self.form_class) + context['service'] = service + context['object'] = self.get_object() + return context + + def form_valid(self, form): + order = form.save(commit=False) + order.conference = self.object + order.save() + messages.success(self.request, _(u'Ваш запрос был успешно отправлен')) + return HttpResponseRedirect(self.success_url) + + def get_initial(self): + """ + Returns the initial data to use for forms on this view. + """ + if self.request.user.is_authenticated(): + user = self.request.user + + initial = {'person_inf': user.get_full_name(), + 'person': user.email, + 'country': user.profile.country.name if user.profile.country else '', + 'city':user.profile.city.name if user.profile.city else '', + 'phone': user.profile.phone if user.profile.phone else ''} -class ConferenceView(ExpoListView): + + + return initial + else: + return self.initial.copy() + + + +class ConferenceDetail(JitterCacheMixin, DetailView): + cache_range = settings.CACHE_RANGE model = Conference - template_name = 'event_catalog.html' + slug_field = 'url' + template_name = 'client/conference/conference_detail.html' + + def get_context_data(self, **kwargs): + context = super(ConferenceDetail, self).get_context_data(**kwargs) + context['advertising_form'] = AdvertiseForm() + return context + +class ConferenceList(MetadataMixin, JitterCacheMixin, ListView): + cache_range = settings.CACHE_RANGE + model = Conference + paginate_by = settings.CLIENT_PAGINATION + template_name = 'client/conference/conference_list.html' + search_form = ExpositionSearchForm + catalog_url = '/conference/' + year = None + month = None + + def get_queryset(self): + if self.request.user.is_staff: + + qs = self.model.objects.upcoming() + else: + qs = self.model.enable.upcoming() + + year = self.kwargs.get('year') + if year: + qs = self.model.enable.filter(data_end__year=year) + # info for breadscrumbs + self.year = {'text': year, 'link': '%s%s/'%(self.catalog_url, year)} + + month = self.kwargs.get('month') + if month and MONTHES.get(month): + qs = qs.filter(data_begin__month=MONTHES[month]['value']) + self.month = {'text': MONTHES[month]['name'], 'link': '%s%s/%s/'%(self.catalog_url, year, month)} + return qs + + def get_context_data(self, **kwargs): + context = super(ConferenceList, self).get_context_data(**kwargs) + context['month'] = self.month + context['catalog_url'] = self.catalog_url + context['search_form'] = self.search_form + context['year'] = self.year + context['month'] = self.month + return context + def conference_add_calendar(request, id): args = {'success': False} @@ -14,38 +389,32 @@ def conference_add_calendar(request, id): if user.is_authenticated(): conf = Conference.objects.safe_get(id=id) - if conf: + if conf in user.calendar.get_confs(): + user.calendar.conferences.remove(conf) + args['in'] = False + else: user.calendar.conferences.add(conf) - args['success'] = True - else: - args['not_authorized'] = True + args['in'] = True args['success'] = True - - return HttpResponse(json.dumps(args), content_type='application/json') - -def conference_remove_calendar(request, id): - args = {'success': False} - if request.user: - user = request.user - conf = Conference.objects.safe_get(id=id) - if conf: - user.calendar.conferences.remove(conf) - args['success'] = True else: args['not_authorized'] = True args['success'] = True - return HttpResponse(json.dumps(args), content_type='application/json') + def conference_visit(request, id): args = {'success': False} user = request.user if user.is_authenticated(): conf = Conference.objects.safe_get(id=id) - if conf: + if user in conf.users.all(): + conf.users.remove(user) + args['in'] = False + else: conf.users.add(user) - args['success'] = True + args['in'] = True + args['success'] = True else: args['not_authorized'] = True @@ -53,18 +422,34 @@ def conference_visit(request, id): return HttpResponse(json.dumps(args), content_type='application/json') -def conference_unvisit(request, id): +def add_note(request, slug): args = {'success': False} - user = request.user - if user.is_authenticated(): - conf = Conference.objects.safe_get(id=id) - if conf: - conf.users.remove(user) - else: - args['not_authorized'] = True - args['success'] = True - return HttpResponse(json.dumps(args), content_type='application/json') + if request.user.is_authenticated(): + if request.GET: + text = request.GET['note_text'] + try: + conf = Conference.objects.get(url=slug) + except Conference.DoesNotExist: + raise Http404 + + ct = ContentType.objects.get_for_model(conf) + object_id = conf.id + user = User.objects.get(id=request.user.id) + if Note.objects.filter(user=user, content_type=ct, object_id=object_id).exists(): + Note.objects.filter(user=user, content_type=ct, object_id=object_id).update(text=text) + else: + Note.objects.create(content_type=ct, object_id=object_id, user=user, text=text) + + user.calendar.conferences.add(conf) + args['success'] = True + args['text'] = text + + else: + args['not_authorized'] = True + args['success'] = True + + return HttpResponse(json.dumps(args), content_type='application/json') \ No newline at end of file diff --git a/core/simple_index_view.py b/core/simple_index_view.py index 1213a94c..bb0cab57 100644 --- a/core/simple_index_view.py +++ b/core/simple_index_view.py @@ -1,23 +1,25 @@ import json from django.views.generic import TemplateView from django.shortcuts import HttpResponse -from forms import CallbackForm +#from forms import CallbackForm +from service.order_forms import CallBackForm +from meta.views import MetadataMixin -class AdvertisingView(TemplateView): +class AdvertisingView(MetadataMixin, TemplateView): template_name = 'simple_pages/advertising.html' -class AboutView(TemplateView): +class AboutView(MetadataMixin, TemplateView): template_name = 'simple_pages/about.html' def callback(request): response = {'success': False} if request.GET: - form = CallbackForm(request.GET) + form = CallBackForm(request.GET) if form.is_valid(): - form.send() + form.save() response['success'] = True else: response['errors'] = form.errors diff --git a/country/management/commands/country_update_from_old.py b/country/management/commands/country_update_from_old.py new file mode 100644 index 00000000..5c70e1f9 --- /dev/null +++ b/country/management/commands/country_update_from_old.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +import MySQLdb +from MySQLdb.cursors import DictCursor +from django.core.management.base import BaseCommand, CommandError +from django.utils import translation +from country.models import Country + + +def get_from_old(country): + db = MySQLdb.connect(host="localhost", + user="kotzilla", + passwd="qazedc", + db="test2", + charset='utf8', + cursorclass=DictCursor) + cursor = db.cursor() + sql = """SELECT url, inflect FROM old_expomap.products_places WHERE title="%(name)s" """%{'name': country.name.encode('utf-8')} + #print(country.name.encode('utf-8')) +# print(sql) + cursor.execute(sql) + result = cursor.fetchone() + + return result + + +class Command(BaseCommand): + def handle(self, *args, **options): + translation.activate('ru') + for country in Country.objects.all(): + old_data = get_from_old(country) + if old_data is None: + continue + country.old_url = old_data['url'] + country.inflect = old_data['inflect'] + try: + country.save() + print(country) + except: + continue \ No newline at end of file diff --git a/country/manager.py b/country/manager.py new file mode 100644 index 00000000..b267551f --- /dev/null +++ b/country/manager.py @@ -0,0 +1,105 @@ +import datetime +from django.utils import translation +from django.core.cache import cache +from django.utils.translation import get_language as lang +from hvad.models import TranslationManager + + +class CountryManager(TranslationManager): + cache_time = 600 + + def all(self): + """ + hack + """ + return super(TranslationManager, self).all().filter(translations__language_code=lang()).order_by('translations__name') + + def safe_get(self, **kwargs): + model = self.model + try: + return model.objects.get(**kwargs) + except: + return None + + def expo_countries(self): + lang = translation.get_language() + key = 'used_expo_countries_%s'%lang + cached_countries = cache.get(key) + if cached_countries: + return cached_countries + else: + from exposition.models import Exposition + countries_id = [item['country_id'] for item in Exposition.objects.values('country_id').distinct()] + countries = list(self.language().filter(id__in=countries_id)) + cache.set(key, countries, self.cache_time) + return countries + + def expo_countries_with_count(self): + lang = translation.get_language() + key = 'used_expo_countries_count_%s'%lang + cached_countries = cache.get(key) + if cached_countries: + return cached_countries + else: + + from exposition.models import Exposition + sql = {'expo_count': + """SELECT COUNT(*) + FROM exposition_exposition + WHERE exposition_exposition.country_id = country_country.id + AND exposition_exposition.data_end >= CURDATE() + AND exposition_exposition.is_published = 1"""} + now = datetime.datetime.now().date() + # id of unique countries + countries_id = [item['country_id'] for item in Exposition.objects.filter(is_published=True, data_end__gte=now).values('country_id').distinct()] + countries = set(list(self.language().filter(id__in=countries_id).extra(select=sql))) + countries = sorted(countries, key=lambda x: x.name) + cache.set(key, countries, self.cache_time) + return countries + + def conference_countries_with_count(self): + lang = translation.get_language() + key = 'used_conference_countries_count_%s'%lang + cached_countries = cache.get(key) + if cached_countries: + return cached_countries + else: + + from conference.models import Conference + sql = {'conference_count': + """SELECT COUNT(*) + FROM conference_conference + WHERE conference_conference.country_id = country_country.id + AND conference_conference.data_end >= CURDATE() + AND conference_conference.is_published = 1"""} + now = datetime.datetime.now().date() + # id of unique countries + countries_id = [item['country_id'] for item in Conference.objects.filter(is_published=True, data_end__gte=now).values('country_id').distinct()] + countries = set(list(self.language().filter(id__in=countries_id).extra(select=sql))) + countries = sorted(countries, key=lambda x: x.name) + cache.set(key, countries, self.cache_time) + return countries + + def conference_countries(self): + lang = translation.get_language() + key = 'used_conference_countries_%s'%lang + cached_countries = cache.get(key) + if cached_countries: + return cached_countries + else: + from conference.models import Conference + countries_id = [item['country_id'] for item in Conference.objects.values('country_id').distinct()] + countries = list(self.language().filter(id__in=countries_id)) + cache.set(key, countries, self.cache_time) + return countries + + +class AreaManager(TranslationManager): + def all_sorted(self): + """ + return list, not queryset + """ + model = self.model + result = list(model.objects.filter()) + result.sort(key=lambda x: len(x.expos()), reverse=True) + return result diff --git a/country/models.py b/country/models.py index 6e954537..d2012dbc 100644 --- a/country/models.py +++ b/country/models.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- from datetime import date from django.db import models -from django.utils.translation import ugettext as _ from django.contrib.contenttypes import generic -from django.db.models.signals import post_save, pre_save -from hvad.models import TranslatableModel, TranslatedFields, TranslationManager +from django.db.models.signals import post_save +from hvad.models import TranslatableModel, TranslatedFields from bitfield import BitField +from manager import CountryManager, AreaManager # models from directories.models import Language, Currency from city.models import City @@ -13,42 +13,18 @@ from service.models import Service from exposition.models import Exposition from place_exposition.models import PlaceExposition from organiser.models import Organiser +from conference.models import Conference +from seminar.models import Seminar +from webinar.models import Webinar # func -from functions.custom_fields import EnumField from functions.db import db_table_exists from functions.signal_handlers import post_save_handler, pre_save_handler -from django.utils.translation import get_language as lang from django.utils import translation + # check if table exist and create flags if true flags = [str(item.url) for item in Service.objects.all()] if db_table_exists('service_service') else [] -class CountryManager(TranslationManager): - def all(self): - """ - hack - """ - return super(TranslationManager, self).all().filter(translations__language_code=lang()).order_by('translations__name') - - def safe_get(self, **kwargs): - model = self.model - try: - return model.objects.get(**kwargs) - except: - return None - -class AreaManager(TranslationManager): - def all_sorted(self): - """ - return list, not queryset - """ - model = self.model - result = list(model.objects.filter()) - result.sort(key=lambda x: len(x.expos()), reverse=True) - return result - - - class Area(TranslatableModel): translations = TranslatedFields( @@ -56,13 +32,16 @@ class Area(TranslatableModel): ) objects = AreaManager() + class Meta: + ordering = ['translations__name'] + def __unicode__(self): return self.lazy_translation_getter('name', unicode(self.pk)) def countries(self): lang = translation.get_language() return Country.objects.select_related('exposition_country')\ - .filter(exposition_country__country__isnull=False, translations__language_code=lang, area=self).distinct() + .filter(exposition_country__country__isnull=False, translations__language_code=lang, area=self).distinct().order_by('translations__name') def expos(self): countries = self.countries() @@ -77,9 +56,6 @@ class Area(TranslatableModel): return parent - - - class Country(TranslatableModel): """ Create Country model @@ -87,12 +63,12 @@ class Country(TranslatableModel): Uses hvad.TranslatableModel which is child of django.db.models class """ - objects = CountryManager() catalog = '/country/' - services = BitField(flags=flags) url = models.SlugField(unique=True) + old_url = models.CharField(unique=True, max_length=55) + inflect = models.CharField(max_length=255, blank=True) # relations area = models.ForeignKey(Area) big_cities = models.ManyToManyField(City, blank=True, null=True, related_name='cities') @@ -104,14 +80,12 @@ class Country(TranslatableModel): teritory = models.PositiveIntegerField(blank=True, null=True) timezone = models.FloatField(blank=True, null=True) phone_code = models.PositiveIntegerField(blank=True, null=True) - time_delivery = models.PositiveSmallIntegerField(blank=True, null=True) latitude = models.FloatField(blank=True, null=True) longitude = models.FloatField(blank=True, null=True) - - # fields saves information about creating and changing model created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) + country_code = models.CharField(max_length=2) # connection with FileModel by ContentType files = generic.GenericRelation('file.FileModel',content_type_field='content_type', object_id_field='object_id') #translated fields @@ -127,12 +101,10 @@ class Country(TranslatableModel): title = models.CharField(max_length=255), descriptions = models.CharField(max_length=255), keywords = models.CharField(max_length=255), - ) - country_code = models.CharField(max_length=2) -# class Meta: -# ordering = ['translations__name'] + class Meta: + ordering = ['translations__name'] def __unicode__(self): return self.lazy_translation_getter('name', unicode(self.pk)) @@ -160,10 +132,24 @@ class Country(TranslatableModel): return len(Exposition.objects.filter(country=self.id)) + def conferences_number(self): + + return Conference.objects.filter(country=self.id).count() + + def seminars_number(self): + + return Seminar.objects.filter(country=self.id).count() + + def webinars_number(self): + + return Webinar.objects.filter(country=self.id).count() + def active_cities(self): + + return City.used.active_qs().filter(country=self) lang = translation.get_language() - return City.objects.select_related('exposition_city')\ - .filter(exposition_city__city__isnull=False, translations__language_code=lang, country=self).distinct() + #return City.objects.select_related('exposition_city')\ + # .filter(exposition_city__city__isnull=False, translations__language_code=lang, country=self).distinct().order_by('translations__name') def get_sub_categories(self): objects = [{'text':item.name, 'id':item.id, 'name':'ci', 'sub': False} for item in self.active_cities()] diff --git a/exposition/admin.py b/exposition/admin.py index e5309b23..a5b1164e 100644 --- a/exposition/admin.py +++ b/exposition/admin.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import json from django.shortcuts import render_to_response from django.http import HttpResponseRedirect, HttpResponse from django.core.context_processors import csrf @@ -8,6 +9,7 @@ from django.forms.models import modelformset_factory from django.contrib.contenttypes.models import ContentType from django.contrib.auth.decorators import login_required # models and forms +from haystack.query import SearchQuerySet from models import Exposition, TimeTable, Statistic, TmpTimeTable from forms import ExpositionCreateForm, ExpositionDeleteForm, TimeTableForm, StatisticForm, ExpositionFilterForm from theme.models import Tag @@ -241,11 +243,11 @@ class ExpositionView(AdminView): template_name = 'admin/exposition/exposition.html' def form_valid(self, form): - StatisticFormSet = formset_factory(StatisticForm) - formset_statistic = StatisticFormSet(self.request.POST) + #StatisticFormSet = formset_factory(StatisticForm) + #formset_statistic = StatisticFormSet(self.request.POST) self.set_obj() expo = form.save(obj=self.obj) - + """ # delete old halls Statistic.objects.filter(exposition=getattr(expo, 'id')).delete() @@ -255,7 +257,7 @@ class ExpositionView(AdminView): statistic = item.save(commit=False) statistic.exposition = expo statistic.save() - + """ return HttpResponseRedirect(self.success_url) @@ -331,20 +333,22 @@ class ExpositionView(AdminView): context = super(ExpositionView, self).get_context_data(**kwargs) obj = self.set_obj() if obj: - StatisticFormSet = modelformset_factory(Statistic, form=StatisticForm, exclude=('exposition',)) + #StatisticFormSet = modelformset_factory(Statistic, form=StatisticForm, exclude=('exposition',)) # get existing statistic - statistic = Statistic.objects.filter(exposition=getattr(obj, 'id')) + #statistic = Statistic.objects.filter(exposition=getattr(obj, 'id')) # fill HallFormSet - formset_statistic = StatisticFormSet(queryset=statistic) + #formset_statistic = StatisticFormSet(queryset=statistic) + context['stat_form'] = StatisticForm() context['file_form'] = FileForm(initial={'model': 'exposition.Exposition'}) files = FileModel.objects.filter(content_type=ContentType.objects.get_for_model(obj),object_id=getattr(obj, 'id')) context['files'] = files else: - StatisticFormSet = formset_factory(StatisticForm) - formset_statistic = StatisticFormSet() + #StatisticFormSet = formset_factory(StatisticForm) + #formset_statistic = StatisticFormSet() + pass - context['formset_statistic'] = formset_statistic + #context['formset_statistic'] = formset_statistic context['photo_form'] = PhotoForm() context['timetable_form'] = TimeTableForm() @@ -358,4 +362,26 @@ class ExpositionListView(AdminListView): def upload_exposition_photo(request, expo_id): - return upload_photo(request, expo_id, Exposition) \ No newline at end of file + return upload_photo(request, expo_id, Exposition) + + +def get_by_lang(item, field, lang='en'): + """ + + :param item: searchresult object + field: translated field + :return: + """ + return getattr(item, field+'_'+lang) +from django.utils import translation + +def search_expo(request): + term = request.GET['term'].capitalize() + lang = translation.get_language() + if not term: + qs = SearchQuerySet().models(Exposition).order_by('text')[:30] + else: + qs = SearchQuerySet().models(Exposition).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') \ No newline at end of file diff --git a/exposition/admin_urls.py b/exposition/admin_urls.py index 402dd4ed..07715753 100644 --- a/exposition/admin_urls.py +++ b/exposition/admin_urls.py @@ -6,13 +6,16 @@ urlpatterns = patterns('exposition.admin', url(r'^upload-photo/(?P.*)/$', 'upload_exposition_photo'), #url(r'^add.*/$', 'exposition_add'), - #url(r'^delete/(?P.*)/$', 'exposition_delete'), + url(r'^delete/(?P.*)/$', 'exposition_delete'), #url(r'^change/(?P.*)/$', 'exposition_change'), url(r'^all/$', ExpositionListView.as_view()), url(r'^switch/(?P.*)/(?P.*)$', 'exposition_switch'), #url(r'^copy/(?P.*)$', 'exposition_copy'), + url(r'^search/$', 'search_expo'), url(r'^(?P.*)/$', ExpositionView.as_view()), + url(r'^$', ExpositionView.as_view()), + ) diff --git a/exposition/forms.py b/exposition/forms.py index cede88a6..be955bc1 100644 --- a/exposition/forms.py +++ b/exposition/forms.py @@ -28,6 +28,8 @@ from functions.admin_forms import AdminFilterForm places = [(item.id, item.name) for item in PlaceExposition.objects.language().all()] places.insert(0,('', 'Не выбрано')) + + class ExpositionCreateForm(forms.Form): """ Create Exposition form for creating exposition @@ -44,7 +46,7 @@ class ExpositionCreateForm(forms.Form): currencies = [(item, item) for item in CURRENCY] data_begin = forms.DateField(label=u'Дата начала', input_formats=['%Y-%m-%d', '%d.%m.%Y']) - data_end = forms.DateField(label=u'Дата окночания', input_formats=['%Y-%m-%d', '%d.%m.%Y']) + 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, @@ -77,13 +79,9 @@ class ExpositionCreateForm(forms.Form): widget=forms.CheckboxSelectMultiple()) # currency = forms.ChoiceField(label=u'Валюта', choices=currencies, required=False) - application_deadline = forms.DateField(label=u'Срок подачи стэнда', required=False) - min_stand_size = forms.CharField(label=u'Минимальный размер стэнда', required=False) + application_deadline = forms.DateField(label=u'Срок подачи стенда', required=False) + min_stand_size = forms.CharField(label=u'Минимальный размер стенда', required=False) - #price_day = forms.CharField(label=u'Цена за 1 день', required=False) - #price_all = forms.CharField(label=u'Цена за все дни', required=False) - #price_day_bar = forms.CharField(label=u'Цена на стойке 1 день', required=False) - #price_all_bar = forms.CharField(label=u'Цена на стойке все дни', required=False) price_catalog = forms.CharField(label=u'Цена за каталог', required=False) tax = forms.BooleanField(label=u'Налог включен', initial=True, required=False) min_closed_area = forms.CharField(label=u'Минимальная цена закрытой НЕ оборудованной площади', required=False) @@ -227,6 +225,8 @@ class ExpositionCreateForm(forms.Form): if data.get('place'): exposition.place = PlaceExposition.objects.get(id=data['place']) + else: + exposition.place = None # fill translated fields and save object fill_with_signal(Exposition, exposition, data) @@ -462,14 +462,48 @@ class ExpositionDeleteForm(forms.ModelForm): fields = ('url',) -class StatisticForm(forms.ModelForm): - year = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'})) - visitors = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'}), required=False) - members = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'}), required=False) - area = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'}), required=False) - class Meta: - model = Statistic - exclude = ('exposition') +class StatisticForm(forms.Form): + year = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'}), label='Год') + visitors = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'}), required=False, label='Посетители') + members = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'}), required=False, label='Участники') + area = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'}), required=False, label='Площадь') + countries_number = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:70px'}), required=False, label='Число стран') + + def __init__(self, *args, **kwargs): + """ + create dynamical translated fields fields + """ + super(StatisticForm, self).__init__(*args, **kwargs) + #creates translated forms example: name_ru, name_en + # len(10) is a hack for detect if settings.LANGUAGES is not configured it return all langs + if len(settings.LANGUAGES) in range(10): + for lid, (code, name) in enumerate(settings.LANGUAGES): + # uses enumerate for detect iteration number + # first iteration is a default lang so it required fields + required = True if lid == 0 else False + self.fields['countries_%s' % code] = forms.CharField(label=u'Участвующие страны', + required=False, + widget=forms.TextInput(attrs={'style':'width: 250px'})) + + def save(self, exposition=None): + data = self.cleaned_data + if not exposition: + return None + else: + stat = Statistic() + + # simple fields + + stat.exposition = exposition + stat.year = data['year'] + stat.visitors = data.get('visitors') + stat.members = data.get('members') + stat.area = data.get('area') + stat.countries_number = data.get('countries_number') + + fill_with_signal(Statistic, stat, data) + + return stat def clean_year(self): cleaned_data = super(StatisticForm, self).clean() @@ -486,6 +520,11 @@ class StatisticForm(forms.ModelForm): visitors = cleaned_data.get('visitors').strip() return is_positive_integer(visitors) + def clean_countries_number(self): + cleaned_data = super(StatisticForm, self).clean() + countries_number = cleaned_data.get('countries_number').strip() + return is_positive_integer(countries_number) + from functions.files import check_tmp_timetables class TimeTableForm(forms.Form): diff --git a/exposition/management/commands/expo_old.py b/exposition/management/commands/expo_old.py new file mode 100644 index 00000000..fdf7135f --- /dev/null +++ b/exposition/management/commands/expo_old.py @@ -0,0 +1,201 @@ +# -*- coding: utf-8 -*- +import os +import MySQLdb +from MySQLdb.cursors import DictCursor +from django.core.management.base import BaseCommand +from django.conf import settings +from exposition.models import Exposition +from conference.management.commands.conf_old import filter_city, filter_country, get_periodic, get_logo, get_places +from django.core.files import File +from functions.translate import fill_with_signal +from country.models import Country +from city.models import City + +file_path = settings.MEDIA_ROOT + 'exposition/bad_expos.txt' + +import datetime +from theme.models import Theme +from conference.models import Conference +''' +class Command(BaseCommand): + def handle(self, *args, **options): + db = MySQLdb.connect(host="localhost", + user="expomap", + passwd="7FbLtAGjse", + db="old_db", + charset='utf8', + cursorclass=DictCursor) + cursor = db.cursor() + conf_old = """ + SELECT DISTINCT (products_to_categories.products_id), url as old_url + FROM `products_to_categories` + LEFT JOIN `products` ON products_to_categories.products_id=products.products_id + LEFT JOIN `products_description` ON products_to_categories.products_id=products_description.products_id + WHERE `products_status` =1 + AND `conference` =0 + + """ + + + find_themes = "SELECT categories_id FROM `products_to_categories` WHERE `products_id` =%d" + + cursor.execute(conf_old) + + conferences = cursor.fetchall() + #for item in conferences: + cursor.execute(find_themes%conferences[0]['products_id']) + + day = datetime.date.today() + day = day.replace(month=1, day=1) + + for item in conferences: + old_url = item['old_url'] + if not old_url: + continue + try: + expo = Exposition.objects.get(old_url=old_url) + except: + continue + if expo.data_begin > day: + continue + + cursor.execute(find_themes%item['products_id']) + + themes_id = [i['categories_id'] for i in cursor.fetchall()] + theme_qs = Theme.objects.filter(id__in=themes_id) + + expo.theme.add(*theme_qs) + print(expo) + + + + + + + # if item['categories_id'] == 0: + # continue + # Theme.objects.get(id=item['categories_id']) + #print(result) +''' + +from haystack.query import SearchQuerySet +from django.db import IntegrityError +from django.utils import translation + +class Command(BaseCommand): + def handle(self, *args, **options): + db = MySQLdb.connect(host="localhost", + user="expomap", + passwd="7FbLtAGjse", + db="old_db", + charset='utf8', + cursorclass=DictCursor) + cursor = db.cursor() + sql = """ + SELECT products.products_id as id, products_date_added as created, products_last_modified as modified, + discount, expohit, ufi, products_name as name, products_description as description, + products_short_description as main_title, products_viewed as viewed, products_period as period, + products_org as organiser,products_products as products, products_official as web_page, + products_img1 as logo, products_startdate as data_begin, products_enddate as data_end, + url as old_url, places_id + FROM `products` + LEFT JOIN `products_description` ON products.products_id=products_description.products_id + WHERE `products_status` =1 + AND `conference` =0 AND places_id >0 + ORDER BY products.products_id DESC + """ + translation.activate('ru') + expos = list(Exposition.objects.language().filter(old_url='')) + find_expo = "SELECT products_name, url from products_description WHERE products_name = '%s'" + + for expo in expos: + cursor.execute(find_expo%expo.name) + result = cursor.fetchall() + if result: + expo.old_url = result[0]['url'] + expo.save() + print(expo) + + #cursor.execute(sql) + #result = cursor.fetchall() + + #names = [item['name'] for item in result] + + + #media = settings.MEDIA_ROOT.replace('media/', '') + #counter = 0 + #bad_cities = {} + + + bad_expos = [] + ''' + for i, item in enumerate(result): + qs = SearchQuerySet().models(Exposition).filter(name_ru=item['name']) + if not item: + continue + if not qs.count()>0: + continue + expo =qs[0].object + + if not expo or expo.old_url: + continue + print(expo) + expo.old_url = item['old_url'] + try: + expo.save() + except IntegrityError: + continue + + + """ + print('number: %d, errors: %d'%(i, len(bad_expos))) + name = item['name'] + if Exposition.objects.filter(translations__name=name).exists(): + msg = u'%s|||%s|||%s'%(name, item['old_url'], 'already exist') + bad_expos.append(msg) + continue + + data_begin = item['data_begin'] + data_end= item['data_end'] + + + place_id = item['places_id'] # convert to country and city + country, city = get_places(place_id) + + if not country or not city: + msg = u'%s|||%s|||%s'%(name, item['old_url'], 'bad country or city') + bad_expos.append(msg) + continue + old_url = item['old_url'] + periodic = item['period'] + periodic = get_periodic(periodic) + web_page = item['web_page'] + currency = 'USD' + expohit = item['expohit'] + ufi = item['ufi'] + if ufi: + ufi = 1 + else: + ufi = 0 + + created = item['created'] + modified = item['modified'] + + data = {'name_ru': name, 'main_title_ru': item['main_title'], 'description_ru': item['description'], + 'products_ru': item['products'], 'discount_description_ru': '', 'time_ru': '', 'price_day_ru':'', + 'price_all_ru': '', 'price_day_bar_ru': '', 'price_all_bar_ru': '', 'stat_countries_ru': '', + 'pre_condition_ru':'', 'stand_condition_ru': '', 'visit_note_ru': '', 'participation_note_ru': '', + 'title_ru': '', 'descriptions_ru': '', 'keywords_ru': ''} + + exposition = Exposition(data_begin=data_begin, data_end=data_end, city=city, country=country, + web_page=web_page, old_url=old_url, periodic=periodic, currency=currency, + expohit=expohit, created=created, modified=modified, quality_label=ufi) + + try: + fill_with_signal(Exposition, exposition, data) + except Exception as e: + msg = u'%s|||%s|||%s'%(name, item['old_url'], str(e)) + bad_expos.append(msg) + continue + """ + ''' diff --git a/exposition/management/commands/expo_organiser.py b/exposition/management/commands/expo_organiser.py new file mode 100644 index 00000000..c0596fe1 --- /dev/null +++ b/exposition/management/commands/expo_organiser.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +import xlrd +from django.core.management.base import BaseCommand +from django.conf import settings +from functions.form_check import translit_with_separator +from exposition.models import Exposition +from organiser.models import Organiser + + +CHINA_FILE = settings.MEDIA_ROOT+'/import/expo_china_ru.xlsx' +GERMANY_FILE = settings.MEDIA_ROOT+'/import/expo_germany_ru.xlsx' +# 391 row not imported(same url) +ITALY_FILE = settings.MEDIA_ROOT+'/import/expo_italy_ru.xlsx' +# moscow 3 exps +F = settings.MEDIA_ROOT+'/import/exp.xlsx' + +LA_FILE = settings.MEDIA_ROOT+'/import/expo_la.xlsx' +NA_EU_ASIA_FILE = settings.MEDIA_ROOT+'/import/expo_na_eu_ sa.xls' +NA_EU_ASIA_FILE2 = settings.MEDIA_ROOT+'/import/expo_na_eu_ sa_part2.xls' +RUSSIA_FILE = settings.MEDIA_ROOT+'/import/expo_russia.xls' + + +class Command(BaseCommand): + def handle(self, *args, **options): + + f = open(RUSSIA_FILE, 'r') + 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)] + labels = [label for label in row_list[0]] + + for row_number, row in enumerate(row_list[1:]): + exp_url = translit_with_separator(row[2]) + try: + exp = Exposition.objects.get(url=exp_url) + except Exposition.DoesNotExist: + continue + + cell1 = row[11].split(';') + cell2 = row[12].split(';') + orgs = [item.strip() for item in cell1+cell2 if item] + exp.organiser.clear() + for org in orgs: + url = translit_with_separator(org) + try: + organiser = Organiser.objects.get(url=url) + except Organiser.DoesNotExist: + organiser = Organiser(url=url) + organiser.translate('ru') + organiser.name = org + organiser.save() + except Organiser.MultipleObjectsReturned: + continue + + + if not exp.organiser.filter(url=organiser.url).exists(): + exp.organiser.add(organiser) + + print(exp) + diff --git a/exposition/management/commands/expo_test.py b/exposition/management/commands/expo_test.py new file mode 100644 index 00000000..4eb39b4e --- /dev/null +++ b/exposition/management/commands/expo_test.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +import xlrd +import urllib2 +from django.core.management.base import BaseCommand +from django.conf import settings +from functions.form_check import translit_with_separator +from functions.files import get_alternative_filename +from exposition.models import Exposition, Statistic +from organiser.models import Organiser + + +CHINA_FILE = settings.MEDIA_ROOT+'/import/expo_china_ru.xlsx' +GERMANY_FILE = settings.MEDIA_ROOT+'/import/expo_germany_ru.xlsx' +# 391 row not imported(same url) +ITALY_FILE = settings.MEDIA_ROOT+'/import/expo_italy_ru.xlsx' +# moscow 3 exps +F = settings.MEDIA_ROOT+'/import/exp.xlsx' + +LA_FILE = settings.MEDIA_ROOT+'/import/expo_la.xlsx' +NA_EU_ASIA_FILE = settings.MEDIA_ROOT+'/import/expo_na_eu_ sa.xls' +NA_EU_ASIA_FILE2 = settings.MEDIA_ROOT+'/import/expo_na_eu_ sa_part2.xls' + +# 44 +class Command(BaseCommand): + def handle(self, *args, **options): + qs = Statistic.objects.language('ru').exclude(translations__countries='') + comas = 0 + enters = 0 + main = 0 + spaces = 0 + word = 0 + number = 0 + for i in qs: + if ';' in i.countries: + main +=1 + a = i.countries.split(';') + new = [item.strip() for item in a] + + st = ';'.join(new) + #print st.encode('utf8') + i.countries = st + #i.save() + elif ',' in i.countries: + comas += 1 + + + elif '\n' in i.countries: + enters += 1 + elif ' ' in i.countries: + spaces += 1 + print(i.countries.encode('utf8')) + if '55' in i.countries: + continue + + + elif '.' in i.countries: + number += 1 + #print(i.countries) + #a = i.countries.split('.') + #i.countries_number = int(a[0]) + #i.countries = '' + #i.save() + + else: + word += 1 + #print(i.countries.encode('utf8')) + + + + print('all: %d'%qs.count()) + print('main: %d'%main) + print('comas: %d'%comas) + print('enter: %d'%enters) + print('spaces: %d'%spaces) + print('word: %d'%word) + print('number: %d'%number) + diff --git a/exposition/management/commands/exposition_load.py b/exposition/management/commands/exposition_load.py index 0195584f..5989b965 100644 --- a/exposition/management/commands/exposition_load.py +++ b/exposition/management/commands/exposition_load.py @@ -4,6 +4,8 @@ from django.core.management.base import BaseCommand from django.conf import settings from exposition.models import Exposition from import_xls.excel_settings import event_sett +from django.db import IntegrityError +from django.utils import translation CHINA_FILE = settings.MEDIA_ROOT+'/import/expo_china_ru.xlsx' GERMANY_FILE = settings.MEDIA_ROOT+'/import/expo_germany_ru.xlsx' @@ -14,35 +16,57 @@ F = settings.MEDIA_ROOT+'/import/exp.xlsx' LA_FILE = settings.MEDIA_ROOT+'/import/expo_la.xlsx' NA_EU_ASIA_FILE = settings.MEDIA_ROOT+'/import/expo_na_eu_ sa.xls' +NA_EU_ASIA_FILE2 = settings.MEDIA_ROOT+'/import/expo_na_eu_ sa_part2.xls' +RUSSIA_FILE = settings.MEDIA_ROOT+'/import/expo_russia.xls' +GEORGIA_FILE = settings.MEDIA_ROOT+'/import/georgia.xls' class Command(BaseCommand): def handle(self, *args, **options): - f = open(NA_EU_ASIA_FILE, 'r') + + f = open(GEORGIA_FILE, 'r') 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)] labels = [label for label in row_list[0]] + existing = 0 + for row_number, row in enumerate(row_list[1:]): - print(row_number) + #print(row_number) + name = row[2] if row[0] != '': # in first column ids + try: object = Exposition.objects.language('ru').get(id=int(row[0])) + existing += 1 except ValueError: object = Exposition() object.translate('ru') + except Exposition.DoesNotExist: object = Exposition(id= int(row[0])) object.translate('ru') + existing += 1 else: # if id blank - its a new place object = Exposition() object.translate('ru') + """ + try: + object = Exposition.objects.language('ru').filter(translations__name=name)[0] + existing += 1 + except IndexError: + pass + """ + + + methods = [] for col_number, cell in enumerate(row): label = labels[col_number] @@ -76,11 +100,16 @@ class Command(BaseCommand): pass else: setattr(object, field_name, value) - #object.save() + try: + object.save() + except IntegrityError: + continue + print('post save %s'% str(object)) - """ + + for method in methods: func = method['func'] if method.get('purpose'): @@ -90,4 +119,5 @@ class Command(BaseCommand): continue else: func(object, method['value']) - """ \ No newline at end of file + + print(existing) diff --git a/exposition/management/commands/fix_logo.py b/exposition/management/commands/fix_logo.py new file mode 100644 index 00000000..4d3f89ce --- /dev/null +++ b/exposition/management/commands/fix_logo.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +import xlrd +import urllib2 +from django.core.management.base import BaseCommand +from django.conf import settings +from functions.form_check import translit_with_separator +from functions.files import get_alternative_filename +from exposition.models import Exposition +from organiser.models import Organiser + + +CHINA_FILE = settings.MEDIA_ROOT+'/import/expo_china_ru.xlsx' +GERMANY_FILE = settings.MEDIA_ROOT+'/import/expo_germany_ru.xlsx' +# 391 row not imported(same url) +ITALY_FILE = settings.MEDIA_ROOT+'/import/expo_italy_ru.xlsx' +# moscow 3 exps +F = settings.MEDIA_ROOT+'/import/exp.xlsx' + +LA_FILE = settings.MEDIA_ROOT+'/import/expo_la.xlsx' +NA_EU_ASIA_FILE = settings.MEDIA_ROOT+'/import/expo_na_eu_ sa.xls' +NA_EU_ASIA_FILE2 = settings.MEDIA_ROOT+'/import/expo_na_eu_ sa_part2.xls' + + +class Command(BaseCommand): + def handle(self, *args, **options): + + f = open(CHINA_FILE, 'r') + 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)] + labels = [label for label in row_list[0]] + + for row_number, row in enumerate(row_list[1:]): + exp_url = translit_with_separator(row[2]) + try: + exp = Exposition.objects.get(url=exp_url) + except Exposition.DoesNotExist: + continue + + if exp.logo or row[19] == '':# or row[16].startswith('http') or row[16].startswith('https') or not row[16].startswith('/') or row[16].startswith('../'): + continue + + path = row[19] + file_name = path.split('/')[-1] + logo_path = exp.logo.field.upload_to + full_path = settings.MEDIA_ROOT + logo_path + + try: + alt_name = get_alternative_filename(full_path, file_name) + except UnicodeEncodeError: + continue + + download_to = full_path+alt_name + + if path.startswith('http') or path.startswith('https'): + url = path + elif path.startswith('/'): + url = 'http://expomap.ru' + path + elif path.startswith('images'): + url = 'http://expomap.ru/' + path + else: + continue + #print('------------------------------------') + #print(path) + #print(url) + #print('------------------------------------') + + try: + response = urllib2.urlopen(url, timeout=15) + except: + continue + if response.code != 200: + continue + + with open(download_to,'wb') as f: + try: + f.write(response.read()) + f.close() + except: + # can be timeout + continue + + exp.logo = logo_path + alt_name + try: + exp.save() + print(exp) + except: + print('logo exception. logo: %s'%exp.logo) + continue diff --git a/exposition/management/commands/imp_stat.py b/exposition/management/commands/imp_stat.py new file mode 100644 index 00000000..2a97a158 --- /dev/null +++ b/exposition/management/commands/imp_stat.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +import xlrd +import urllib2 +from django.core.management.base import BaseCommand +from django.conf import settings +from functions.form_check import translit_with_separator +from functions.files import get_alternative_filename +from exposition.models import Exposition, Statistic +from organiser.models import Organiser + + +CHINA_FILE = settings.MEDIA_ROOT+'/import/expo_china_ru.xlsx' +GERMANY_FILE = settings.MEDIA_ROOT+'/import/expo_germany_ru.xlsx' +# 391 row not imported(same url) +ITALY_FILE = settings.MEDIA_ROOT+'/import/expo_italy_ru.xlsx' +# moscow 3 exps +F = settings.MEDIA_ROOT+'/import/exp.xlsx' + +LA_FILE = settings.MEDIA_ROOT+'/import/expo_la.xlsx' +NA_EU_ASIA_FILE = settings.MEDIA_ROOT+'/import/expo_na_eu_ sa.xls' +NA_EU_ASIA_FILE2 = settings.MEDIA_ROOT+'/import/expo_na_eu_ sa_part2.xls' +RUSSIA_FILE = settings.MEDIA_ROOT+'/import/expo_russia.xls' + + +class Command(BaseCommand): + def handle(self, *args, **options): + + f = open(RUSSIA_FILE, 'r') + 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)] + labels = [label for label in row_list[0]] + + for row_number, row in enumerate(row_list[1:]): + exp_url = translit_with_separator(row[2]) + try: + exp = Exposition.objects.language('ru').get(url=exp_url) + except Exposition.DoesNotExist: + continue + if not row[30]: + continue + + year = int(row[30]) + + + try: + countries_number = int(exp.stat_countries) + countries = '' + except ValueError: + countries_number = None + countries = exp.stat_countries + + members = exp.members + visitors = exp.visitors + area = exp.area + + + s = Statistic(exposition=exp, + year=year, + countries_number=countries_number, + members=members, + visitors=visitors, + area=area) + s.translate('ru') + s.countries = countries + s.save() + + print(exp) diff --git a/exposition/management/commands/test.py b/exposition/management/commands/test.py new file mode 100644 index 00000000..271b6d8d --- /dev/null +++ b/exposition/management/commands/test.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from django.core.management.base import BaseCommand +from meta.models import MetaSetting + + +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() + + + + + + diff --git a/exposition/manager.py b/exposition/manager.py index 4e8ee528..1c9deec7 100644 --- a/exposition/manager.py +++ b/exposition/manager.py @@ -5,9 +5,10 @@ from hvad.models import TranslationManager class ClientManager(TranslationManager): def get_query_set(self): - now = datetime.datetime.now().date() - return super(ClientManager, self).get_query_set().filter(is_published=True, data_begin__gte=now).order_by('data_begin') + return self.language().select_related('country', 'city', 'place').filter(is_published=True).order_by('data_begin') + def upcoming(self): + return self.filter(data_begin__gte=datetime.datetime.now().date()) """ diff --git a/exposition/models.py b/exposition/models.py index 4d54b967..5fb497ff 100644 --- a/exposition/models.py +++ b/exposition/models.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import copy, datetime from django.db import models +from django.db.models import Q from django.db.models.signals import post_save, pre_save from django.utils.translation import ugettext as _ from django.utils import translation @@ -19,6 +20,8 @@ from functions.model_mixin import EventMixin, ExpoMixin from functions.translate import fill_with_signal from photologue.models import Gallery from import_xls.model_utils import ExpoImportManager +from functions.models_methods import hvad_to_dict + AUDIENCE1 = ((None,_(u'Не выбрано')), ('experts', _(u'Специалисты')), @@ -28,14 +31,13 @@ AUDIENCE1 = ((None,_(u'Не выбрано')), AUDIENCE = (None,'experts', 'experts and consumers', 'general public') -BIT_AUDIENCE = (('experts', _(u'Специалисты')), ('experts and consumers', _(u'Специалисты и потребители')), - ('general public', _(u'Широкая публика'))) +BIT_AUDIENCE = settings.BIT_AUDIENCE -CURRENCY = ('RUB', 'USD', 'EUR', 'RMB', 'GBP') +CURRENCY = settings.CURRENCY # check if table exist and create flags if true -flags = [str(item.id) for item in Service.objects.all()] if db_table_exists('service_service') else [] +flags = [item.url for item in Service.objects.all()] if db_table_exists('service_service') else [] class Exposition(TranslatableModel, EventMixin, ExpoMixin): @@ -52,6 +54,7 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): event_type = 'expo' url = models.SlugField(unique=True, max_length=255) + old_url = models.SlugField(unique=True, max_length=255) data_begin = models.DateField(verbose_name='Дата начала') data_end = models.DateField(verbose_name='Дата окончания') services = BitField(flags=flags) @@ -161,8 +164,19 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): def __unicode__(self): return self.lazy_translation_getter('name', unicode(self.pk)) + def get_services(self): + + country_ids = [item for item, bool in self.country.services if bool==True] + ids = [item for item, bool in self.services if bool==True] + + qs = Service.objects.language().filter(Q(Q(url__in=country_ids) & Q(type=Service.type.expo)) | Q(url__in=ids)) + + return list(qs) + def get_parent(self): return {} + def get_absolute_url(self): + return self.get_permanent_url() def get_index_text(self): translation.activate('ru') @@ -231,7 +245,7 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): for k, v in BIT_AUDIENCE: for item in checked: if item == k: - audience.append(v) + audience.append(unicode(v)) return ', '.join(audience) @@ -246,7 +260,7 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): if self.theme.all(): theme = self.theme.all()[0] now = datetime.datetime.now() - now = now.replace(day=now.day-1) + now = now - datetime.timedelta(days=1) expositions = Exposition.objects.filter(theme__in=[theme], data_begin__gt=now).exclude(id=self.id).order_by('data_begin') return expositions[:3] else: @@ -284,58 +298,22 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): return code return cur - def clone(self): - """ - Return an identical copy of the instance with a new ID. - """ - if not self.pk: - raise ValueError('Instance must be saved before it can be cloned.') - - duplicate = copy.copy(self) - # Setting pk to None. Django thinking this is a new object. - duplicate.pk = None - # url must be unique - duplicate.url += '_copy' - if Exposition.objects.safe_get(url=duplicate.url): - #already has copy this instance - return - - # duplicate should not be published - duplicate.is_published = False - duplicate.cancel_by_administrator = False - - 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.save() - # but lost all ManyToMany relations and Translations. - - # 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 - -class Statistic(models.Model): +class Statistic(TranslatableModel): exposition = models.ForeignKey(Exposition, related_name='statistic') year = models.PositiveIntegerField(verbose_name='Год') - members = models.PositiveIntegerField(verbose_name='Посетители') - visitors = models.PositiveIntegerField(verbose_name='Участники') - area = models.PositiveIntegerField(verbose_name='Площадь') + members = models.PositiveIntegerField(verbose_name='Посетители', blank=True, null=True) + visitors = models.PositiveIntegerField(verbose_name='Участники', blank=True, null=True) + area = models.PositiveIntegerField(verbose_name='Площадь', blank=True, null=True) + countries_number = models.PositiveIntegerField(verbose_name='Количество стран', blank=True, null=True) + + translations = TranslatedFields( + countries = models.TextField(blank=True) + ) + + def to_dict(self): + return hvad_to_dict(self) -from django.core import serializers -from functions.models_methods import hvad_to_dict class TimeTable(TranslatableModel): """ @@ -379,34 +357,10 @@ class TmpTimeTable(TranslatableModel): place = models.CharField(verbose_name='Место проведения', max_length=255, blank=True) ) - def clone(self, exposition=None): - """ - Return an identical copy of the instance with a new ID. - """ - if not self.pk: - raise ValueError('Instance must be saved before it can be cloned.') - - duplicate = copy.copy(self) - # Setting pk to None. Django thinking this is a new object. - duplicate.pk = None - duplicate.exposition = exposition - - - 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.save() - return duplicate pre_save.connect(pre_save_handler, sender=Exposition) post_save.connect(post_save_handler, sender=Exposition) post_save.connect(post_save_handler, sender=TimeTable) -post_save.connect(post_save_handler, sender=TmpTimeTable) \ No newline at end of file +post_save.connect(post_save_handler, sender=TmpTimeTable) +post_save.connect(post_save_handler, sender=Statistic) \ No newline at end of file diff --git a/exposition/search_indexes.py b/exposition/search_indexes.py index 906c835e..630015b9 100644 --- a/exposition/search_indexes.py +++ b/exposition/search_indexes.py @@ -48,4 +48,7 @@ class ExpositionIndex(indexes.SearchIndex, indexes.Indexable, ExpoSearchMixin): elif lang=='en': return self.name_en else: - return self.name_ru \ No newline at end of file + 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 02c4b8af..71816f65 100644 --- a/exposition/urls.py +++ b/exposition/urls.py @@ -4,82 +4,80 @@ from views import ExpositionStatistic, ExpositionPrice,\ ExpositionProgramme, ExpositionSearchView, ExpositionByCountry, ExpositionByTheme, ExpositionByCity -from django.http import HttpResponse +from django.views.decorators.cache import cache_page from views import ExpositionServiceView from views import ExpoCountryCatalog, ExpoCityCatalog, ExpoThemeCatalog, ExpoTagCatalog, ExpoList, ExpoDetail,\ ExpoVisitors, ExpoMembers urlpatterns = patterns('', - url(r'expo/add-note/(?P.*)/$', 'exposition.views.add_note'), - url(r'exposition-add-calendar/(?P\d+)/$', 'exposition.views.exposition_add_calendar'), - url(r'exposition-visit/(?P\d+)/$', 'exposition.views.exposition_visit'), + url(r'^expo/add-note/(?P.*)/$', 'exposition.views.add_note'), + url(r'^exposition-add-calendar/(?P\d+)/$', 'exposition.views.exposition_add_calendar'), + url(r'^exposition-visit/(?P\d+)/$', 'exposition.views.exposition_visit'), # search - url(r'expo/search/', ExpositionSearchView.as_view()), - + url(r'^expo/search/', ExpositionSearchView.as_view()), # country catalog - url(r'expo/country/$', ExpositionByCountry.as_view()), - url(r'expo/country/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', ExpoCountryCatalog.as_view()), - url(r'expo/country/(?P.*)/(?P\d+)/page/(?P\d+)/$', ExpoCountryCatalog.as_view()), - url(r'expo/country/(?P.*)/page/(?P\d+)/$', ExpoCountryCatalog.as_view()), - url(r'expo/country/(?P.*)/(?P\d+)/(?P.*)/$', ExpoCountryCatalog.as_view()), - url(r'expo/country/(?P.*)/(?P\d+)/$', ExpoCountryCatalog.as_view()), - url(r'expo/country/(?P.*)/$', ExpoCountryCatalog.as_view()), + url(r'^expo/country/$', ExpositionByCountry.as_view(), {'meta_id':54}), + url(r'^expo/country/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', ExpoCountryCatalog.as_view(), {'meta_id':7}), + url(r'^expo/country/(?P.*)/(?P\d+)/page/(?P\d+)/$', ExpoCountryCatalog.as_view(), {'meta_id':6}), + url(r'^expo/country/(?P.*)/page/(?P\d+)/$', ExpoCountryCatalog.as_view(), {'meta_id':5}), + url(r'^expo/country/(?P.*)/(?P\d+)/(?P.*)/$', ExpoCountryCatalog.as_view(), {'meta_id':7}), + url(r'^expo/country/(?P.*)/(?P\d+)/$', ExpoCountryCatalog.as_view(), {'meta_id':6}), + url(r'^expo/country/(?P.*)/$', ExpoCountryCatalog.as_view(), {'meta_id':5}), # city catalog - url(r'expo/city/$', ExpositionByCity.as_view()), - url(r'expo/city/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', ExpoCityCatalog.as_view()), - url(r'expo/city/(?P.*)/(?P\d+)/page/(?P\d+)/$', ExpoCityCatalog.as_view()), - url(r'expo/city/(?P.*)/page/(?P\d+)/$', ExpoCityCatalog.as_view()), - url(r'expo/city/(?P.*)/(?P\d+)/(?P.*)/$', ExpoCityCatalog.as_view()), - url(r'expo/city/(?P.*)/(?P\d+)/$', ExpoCityCatalog.as_view()), - url(r'expo/city/(?P.*)/$', ExpoCityCatalog.as_view()), + url(r'^expo/city/$', ExpositionByCity.as_view(), {'meta_id':53}), + url(r'^expo/city/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', ExpoCityCatalog.as_view(), {'meta_id':10}), + url(r'^expo/city/(?P.*)/(?P\d+)/page/(?P\d+)/$', ExpoCityCatalog.as_view(), {'meta_id':9}), + url(r'^expo/city/(?P.*)/page/(?P\d+)/$', ExpoCityCatalog.as_view(), {'meta_id':8}), + url(r'^expo/city/(?P.*)/(?P\d+)/(?P.*)/$', ExpoCityCatalog.as_view(), {'meta_id':10}), + url(r'^expo/city/(?P.*)/(?P\d+)/$', ExpoCityCatalog.as_view(), {'meta_id':9}), + url(r'^expo/city/(?P.*)/$', ExpoCityCatalog.as_view(), {'meta_id':8}), # theme catalog - url(r'expo/theme/$', ExpositionByTheme.as_view()), - url(r'expo/theme/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', ExpoThemeCatalog.as_view()), - url(r'expo/theme/(?P.*)/(?P\d+)/page/(?P\d+)/$', ExpoThemeCatalog.as_view()), - url(r'expo/theme/(?P.*)/page/(?P\d+)/$', ExpoThemeCatalog.as_view()), - url(r'expo/theme/(?P.*)/(?P\d+)/(?P.*)/$', ExpoThemeCatalog.as_view()), - url(r'expo/theme/(?P.*)/(?P\d+)/$', ExpoThemeCatalog.as_view()), - url(r'expo/theme/(?P.*)/$', ExpoThemeCatalog.as_view()), + url(r'^expo/theme/$', ExpositionByTheme.as_view(), {'meta_id':55}), + url(r'^expo/theme/(?P.*)/country/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', ExpoThemeCatalog.as_view(), {'meta_id':44}), + url(r'^expo/theme/(?P.*)/country/(?P.*)/(?P\d+)/(?P.*)/$', ExpoThemeCatalog.as_view(), {'meta_id':44}), + url(r'^expo/theme/(?P.*)/country/(?P.*)/(?P\d+)/page/(?P\d+)/$', ExpoThemeCatalog.as_view(), {'meta_id':44}), + url(r'^expo/theme/(?P.*)/country/(?P.*)/(?P\d+)/$', ExpoThemeCatalog.as_view(), {'meta_id':44}), + url(r'^expo/theme/(?P.*)/country/(?P.*)/page/(?P\d+)/$', ExpoThemeCatalog.as_view(), {'meta_id':44}), + url(r'^expo/theme/(?P.*)/country/(?P.*)/$', ExpoThemeCatalog.as_view(), {'meta_id':44}), + + url(r'^expo/theme/(?P.*)/city/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', ExpoThemeCatalog.as_view(), {'meta_id':42}), + url(r'^expo/theme/(?P.*)/city/(?P.*)/(?P\d+)/(?P.*)/$', ExpoThemeCatalog.as_view(), {'meta_id':42}), + url(r'^expo/theme/(?P.*)/city/(?P.*)/(?P\d+)/page/(?P\d+)/$', ExpoThemeCatalog.as_view(), {'meta_id':42}), + url(r'^expo/theme/(?P.*)/city/(?P.*)/(?P\d+)/$', ExpoThemeCatalog.as_view(), {'meta_id':42}), + + url(r'^expo/theme/(?P.*)/city/(?P.*)/page/(?P\d+)/$', ExpoThemeCatalog.as_view(), {'meta_id':42}), + url(r'^expo/theme/(?P.*)/city/(?P.*)/$', ExpoThemeCatalog.as_view(), {'meta_id':42}), + url(r'^expo/theme/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', ExpoThemeCatalog.as_view(), {'meta_id':13}), + url(r'^expo/theme/(?P.*)/(?P\d+)/page/(?P\d+)/$', ExpoThemeCatalog.as_view(), {'meta_id':12}), + url(r'^expo/theme/(?P.*)/page/(?P\d+)/$', ExpoThemeCatalog.as_view(), {'meta_id':11}), + url(r'^expo/theme/(?P.*)/(?P\d+)/(?P.*)/$', ExpoThemeCatalog.as_view(), {'meta_id':13}), + url(r'^expo/theme/(?P.*)/(?P\d+)/$', ExpoThemeCatalog.as_view(), {'meta_id':12}), + url(r'^expo/theme/(?P.*)/$', ExpoThemeCatalog.as_view(), {'meta_id':11}), # tag catalog - url(r'expo/tag/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', ExpoTagCatalog.as_view()), - url(r'expo/tag/(?P.*)/(?P\d+)/page/(?P\d+)/$', ExpoTagCatalog.as_view()), - url(r'expo/tag/(?P.*)/page/(?P\d+)/$', ExpoTagCatalog.as_view()), - url(r'expo/tag/(?P.*)/(?P\d+)/(?P.*)/$', ExpoTagCatalog.as_view()), - url(r'expo/tag/(?P.*)/(?P\d+)/$', ExpoTagCatalog.as_view()), - url(r'expo/tag/(?P.*)/$', ExpoTagCatalog.as_view()), + url(r'^expo/tag/(?P.*)/(?P\d+)/(?P.*)/page/(?P\d+)/$', ExpoTagCatalog.as_view(), {'meta_id':17}), + url(r'^expo/tag/(?P.*)/(?P\d+)/page/(?P\d+)/$', ExpoTagCatalog.as_view(), {'meta_id':15}), + url(r'^expo/tag/(?P.*)/page/(?P\d+)/$', ExpoTagCatalog.as_view(), {'meta_id':14}), + url(r'^expo/tag/(?P.*)/(?P\d+)/(?P.*)/$', ExpoTagCatalog.as_view(), {'meta_id':17}), + url(r'^expo/tag/(?P.*)/(?P\d+)/$', ExpoTagCatalog.as_view(), {'meta_id':15}), + url(r'^expo/tag/(?P.*)/$', ExpoTagCatalog.as_view(), {'meta_id':14}), # expo additional pages - url(r'expo/(?P.*)/statistic/$', ExpositionStatistic.as_view()), - url(r'expo/(?P.*)/price/$', ExpositionPrice.as_view()), - url(r'expo/(?P.*)/program/$', ExpositionProgramme.as_view()), - url(r'expo/(?P.*)/visitors/page/(?P\d+)/$', ExpoVisitors.as_view()), - url(r'expo/(?P.*)/visitors/$', ExpoVisitors.as_view()), - url(r'expo/(?P.*)/members/page/(?P\d+)/$', ExpoMembers.as_view()), - url(r'expo/(?P.*)/members/$', ExpoMembers.as_view()), - url(r'expo/(?P.*)/service/(?P.*)/', ExpositionServiceView.as_view()), - + url(r'^expo/(?P.*)/statistic/$', ExpositionStatistic.as_view(), {'meta_id':60}), + url(r'^expo/(?P.*)/price/$', ExpositionPrice.as_view(), {'meta_id':61}), + url(r'^expo/(?P.*)/program/$', ExpositionProgramme.as_view(), {'meta_id':62}), + url(r'^expo/(?P.*)/visitors/page/(?P\d+)/$', ExpoVisitors.as_view(), {'meta_id':64}), + url(r'^expo/(?P.*)/visitors/$', ExpoVisitors.as_view(), {'meta_id':64}), + 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/(?P.*)/', ExpositionServiceView.as_view()), # expo list - url(r'expo/(?P\d+)/(?P.*)/page/(?P\d+)/$', ExpoList.as_view()), - url(r'expo/(?P\d+)/page/(?P\d+)/$', ExpoList.as_view()), - url(r'expo/(?P\d+)/(?P.*)/$', ExpoList.as_view()), - url(r'expo/(?P\d+)/$', ExpoList.as_view()), - url(r'expo/page/(?P\d+)/$', ExpoList.as_view()), + url(r'^expo/(?P\d+)/(?P.*)/page/(?P\d+)/$', ExpoList.as_view(), {'meta_id':4}), + url(r'^expo/(?P\d+)/page/(?P\d+)/$', ExpoList.as_view(), {'meta_id':3}), + url(r'^expo/(?P\d+)/(?P.*)/$', ExpoList.as_view(), {'meta_id':4}), + url(r'^expo/(?P\d+)/$', ExpoList.as_view(), {'meta_id':3}), + url(r'^expo/page/(?P\d+)/$', ExpoList.as_view(), {'meta_id':2}), # expo page - url(r'expo/(?P.*)/$', ExpoDetail.as_view()),# event - url(r'expo/$', ExpoList.as_view()), - - - - - - - - - #url(r'expo/(?P.*)/service/(?P.*)/$', ExpositionServiceView.as_view()), - - #url(r'expo/(?P.*)/service/(?P.*)/$', ExpositionServiceView.as_view()), - #url(r'expo/(?P.*)/statistic/$', ExpositionStatistic.as_view()), - - + url(r'^expo/(?P.*)/$', ExpoDetail.as_view(), {'meta_id':18}),# event + url(r'^expo/$', ExpoList.as_view() , {'meta_id':2}), ) diff --git a/exposition/views.py b/exposition/views.py index 9f5bcb93..13ea4857 100644 --- a/exposition/views.py +++ b/exposition/views.py @@ -7,7 +7,7 @@ from django.contrib.contenttypes.models import ContentType from django.conf import settings from django.views.generic import ListView, DetailView from django.utils.translation import ugettext as _ -from django.shortcuts import get_object_or_404 +from django.shortcuts import get_object_or_404, render_to_response from django.http import Http404 from django.utils import translation #models @@ -19,18 +19,19 @@ from country.models import Country from city.models import City from theme.models import Theme, Tag from note.models import Note -from functions.custom_views import ExpoSearchView +from service.order_forms import AdvertiseForm from functions.search_forms import ExpositionSearchForm from functions.custom_views import ExpoSearchView +from meta.views import MetadataMixin +from functions.cache_mixin import JitterCacheMixin, CacheMixin -class ExpositionBy(ListView): +class ExpositionBy(JitterCacheMixin, MetadataMixin, ListView): template_name = 'exposition/exposition_by.html' title1 = '' title2 = '' - """ abstact class """ @@ -42,47 +43,54 @@ class ExpositionBy(ListView): class ExpositionByCountry(ExpositionBy): + cache_range = settings.CACHE_RANGE model = Country title1 = _(u'По странам') title2 = _(u'Выставки мира по странам') catalog = 'country/' def get_queryset(self): - lang = translation.get_language() - return self.model.objects.select_related('exposition_country')\ - .filter(exposition_country__country__isnull=False, translations__language_code=lang)\ - .order_by('translations__name').distinct() + return self.model.objects.expo_countries_with_count() + #lang = translation.get_language() + #return self.model.objects.select_related('exposition_country')\ + # .filter(exposition_country__country__isnull=False, translations__language_code=lang)\ + # .order_by('translations__name').distinct() class ExpositionByTheme(ExpositionBy): + cache_range = settings.CACHE_RANGE model = Theme title1 = _(u'По тематикам') title2 = _(u'Выставки мира по тематикам') catalog = 'theme/' def get_queryset(self): - lang = translation.get_language() - return self.model.objects.select_related('exposition_themes')\ - .filter(exposition_themes__theme__isnull=False, translations__language_code=lang)\ - .order_by('translations__name').distinct() + return self.model.active.expo_themes_with_count() + #lang = translation.get_language() + #return self.model.objects.select_related('exposition_themes')\ + # .filter(exposition_themes__theme__isnull=False, translations__language_code=lang)\ + # .order_by('translations__name').distinct() class ExpositionByCity(ExpositionBy): + cache_range = settings.CACHE_RANGE model = City title1 = _(u'По городам') title2 = _(u'Выставки мира по городам') catalog = 'city/' def get_queryset(self): - lang = translation.get_language() - return self.model.objects.select_related('exposition_city')\ - .filter(exposition_city__city__isnull=False, translations__language_code=lang)\ - .order_by('translations__name').distinct() + return self.model.used.expo_cities_with_count() + #return self.model.used.expo_cities() + #lang = translation.get_language() + #return self.model.objects.select_related('exposition_city')\ + # .filter(exposition_city__city__isnull=False, translations__language_code=lang)\ + # .order_by('translations__name').distinct() class ExpositionSearchView(ExpoSearchView): #paginate_by = 10 - template_name = 'exposition/search.html' + template_name = 'client/exposition/search.html' search_form = ExpositionSearchForm model = Exposition @@ -119,12 +127,6 @@ def exposition_visit(request, id): args['in'] = True args['success'] = True - """ - if exp: - exp.users.add(user) - args['success'] = True - """ - else: args['not_authorized'] = True args['success'] = True @@ -133,34 +135,48 @@ def exposition_visit(request, id): #------------------------------------------------------------------------------ -class ExpoDetail(DetailView): +class ExpoDetail(JitterCacheMixin, MetadataMixin, DetailView): + cache_range = settings.CACHE_RANGE model = Exposition slug_field = 'url' template_name = 'client/exposition/exposition_detail.html' -class ExpositionProgramme(DetailView): + def get_context_data(self, **kwargs): + context = super(ExpoDetail, self).get_context_data(**kwargs) + context['advertising_form'] = AdvertiseForm() + return context + +class ExpositionProgramme(MetadataMixin, DetailView): model = Exposition slug_field = 'url' template_name = 'client/exposition/programm.html' -class ExpositionPrice(DetailView): +class ExpositionPrice(MetadataMixin, DetailView): model = Exposition slug_field = 'url' template_name = 'client/exposition/price.html' -class ExpositionStatistic(DetailView): +class ExpositionStatistic(MetadataMixin, DetailView): model = Exposition slug_field = 'url' template_name = 'client/exposition/statistic.html' from django.views.generic.edit import FormMixin, ModelFormMixin -class ExpositionServiceView(FormMixin, DetailView): +class ExpositionServiceView(MetadataMixin, FormMixin, DetailView): model = Exposition slug_field = 'url' service = None + success_url = '/service/thanks/' + + def dispatch(self, request, *args, **kwargs): + service_url = self.kwargs.get('service_url') + service = get_object_or_404(Service, url=service_url) + self.service = service + self.template_name = service.template + return super(ExpositionServiceView, self).dispatch(request, *args, **kwargs) def post(self, request, *args, **kwargs): self.object = self.get_object() @@ -176,17 +192,16 @@ class ExpositionServiceView(FormMixin, DetailView): return self.form_invalid(form) def get_context_data(self, **kwargs): + kwargs.update({'meta_id': getattr(self.service, 'meta_id','')}) + context = super(ExpositionServiceView, self).get_context_data(**kwargs) service_url = self.kwargs.get('service_url') - service = get_object_or_404(Service, url=service_url) - self.service = service - self.template_name = service.template form = order_forms.get(service_url) self.form_class = form if not form: raise Http404 context['form'] = self.get_form(self.form_class) - context['service'] = service + context['service'] = self.service context['object'] = self.get_object() return context @@ -195,7 +210,7 @@ class ExpositionServiceView(FormMixin, DetailView): order.exposition = self.object order.save() messages.success(self.request, _(u'Ваш запрос был успешно отправлен')) - return HttpResponseRedirect(self.request.path) + return HttpResponseRedirect(self.success_url) def get_initial(self): """ @@ -217,7 +232,8 @@ class ExpositionServiceView(FormMixin, DetailView): return self.initial.copy() -class ExpoList(ListView): +class ExpoList(MetadataMixin, JitterCacheMixin, ListView): + cache_range = settings.CACHE_RANGE model = Exposition paginate_by = settings.CLIENT_PAGINATION template_name = 'client/exposition/exposition_list.html' @@ -228,15 +244,12 @@ class ExpoList(ListView): def get_queryset(self): if self.request.user.is_staff: - now = datetime.datetime.now().date() - qs = self.model.objects.filter(data_begin__gte=now).order_by('data_begin') + qs = self.model.objects.upcoming() else: - qs = self.model.enable.all() - - + qs = self.model.enable.upcoming() year = self.kwargs.get('year') if year: - qs = qs.filter(data_begin__year=year) + qs = self.model.enable.filter(data_end__year=year) # info for breadscrumbs self.year = {'text': year, 'link': '%s%s/'%(self.catalog_url, year)} @@ -255,14 +268,9 @@ class ExpoList(ListView): context['month'] = self.month return context -MONTHES = {'jan': {'value': 1, 'name': _(u'Январь')}, 'feb': {'value': 2, 'name': _(u'Февраль')}, - 'mar': {'value': 3, 'name': _(u'Март')}, 'apr': {'value': 4, 'name': _(u'Апрель')}, - 'may': {'value': 5, 'name': _(u'Май')}, 'jun': {'value': 6, 'name': _(u'Июнь')}, - 'jul': {'value': 7, 'name': _(u'Июль')}, 'aug': {'value': 8, 'name': _(u'Август')}, - 'sep': {'value': 9, 'name': _(u'Сентябрь')}, 'oct': {'value': 10, 'name': _(u'Октябрь')}, - 'nov': {'value': 11, 'name': _(u'Ноябрь')}, 'dec': {'value': 12, 'name': _(u'Декабрь')}} +MONTHES = settings.MONTHES -class ExpoCatalog(ListView): +class ExpoCatalog(MetadataMixin, ListView): model = Exposition paginate_by = settings.CLIENT_PAGINATION template_name = 'exposition/catalog.html' @@ -270,6 +278,8 @@ class ExpoCatalog(ListView): filter_object = None year = None month = None + country = None + city = None def get_filtered_qs(self): # diferent for views @@ -280,11 +290,24 @@ class ExpoCatalog(ListView): year = self.kwargs.get('year') if year: - qs = qs.filter(data_begin__year=year) + qs = self.model.enable.filter(data_end__year=year) + filter_object = self.filter_object + if isinstance(filter_object, Country): + qs = qs.filter(country=filter_object) + elif isinstance(filter_object, City): + qs = qs.filter(city=filter_object) + elif isinstance(filter_object, Theme): + qs = qs.filter(theme=filter_object) + if self.kwargs.get('country'): + qs = qs.filter(country=self.kwargs.get('country')) + if self.kwargs.get('city'): + qs = qs.filter(city=self.kwargs.get('city')) + elif isinstance(filter_object, Tag): + qs = qs.filter(tag=filter_object) + # info for breadscrumbs self.year = {'text': year, 'link': '%s%s/%s/'%(self.catalog_url, self.filter_object.url, year)} - month = self.kwargs.get('month') monthes = {'jan': {'value': 1, 'name': _(u'Январь')}, 'feb': {'value': 2, 'name': _(u'Февраль')}, 'mar': {'value': 3, 'name': _(u'Март')}, 'apr': {'value': 4, 'name': _(u'Апрель')}, @@ -294,7 +317,14 @@ class ExpoCatalog(ListView): 'nov': {'value': 11, 'name': _(u'Ноябрь')}, 'dec': {'value': 12, 'name': _(u'Декабрь')}} if month and monthes.get(month): qs = qs.filter(data_begin__month=monthes[month]['value']) - self.month = {'text': monthes[month]['name'], 'link': '%s%s/%s/%s/'%(self.catalog_url, self.filter_object.url, year, month)} + if self.country: + self.month = {'text': monthes[month]['name'], 'link': '%s%s/country/%s/%s/%s/'% + (self.catalog_url, self.filter_object.url, self.country.url, year, month)} + elif self.city: + self.month = {'text': monthes[month]['name'], 'link': '%s%s/city/%s/%s/%s/'% + (self.catalog_url, self.filter_object.url, self.city.url, year, month)} + else: + self.month = {'text': monthes[month]['name'], 'link': '%s%s/%s/%s/'%(self.catalog_url, self.filter_object.url, year, month)} return qs.order_by('data_begin') @@ -314,8 +344,9 @@ class ExpoCountryCatalog(ExpoCatalog): #this method used in parent get_queryset slug = self.kwargs.get('slug') country = get_object_or_404(Country, url=slug) + self.kwargs['country'] = country self.filter_object = country - qs = self.model.enable.filter(country=country) + qs = self.model.enable.upcoming().filter(country=country) return qs class ExpoCityCatalog(ExpoCatalog): @@ -324,21 +355,51 @@ class ExpoCityCatalog(ExpoCatalog): #this method used in parent get_queryset slug = self.kwargs.get('slug') city = get_object_or_404(City, url=slug) - qs = self.model.enable.filter(city=city) + self.kwargs['city'] = city + qs = self.model.enable.upcoming().filter(city=city) self.filter_object = city return qs class ExpoThemeCatalog(ExpoCatalog): + template_name = 'exposition/catalog_theme.html' catalog_url = '/expo/theme/' + country = None + city = None + def get_filtered_qs(self): #this method used in parent get_queryset slug = self.kwargs.get('slug') + country_slug = self.kwargs.get('country_slug') + city_slug = self.kwargs.get('city_slug') theme = get_object_or_404(Theme, url=slug) - qs = self.model.enable.filter(theme=theme) + self.kwargs['theme'] = theme + + qs = self.model.enable.upcoming().filter(theme=theme) + if country_slug: + country = get_object_or_404(Country, url=country_slug) + self.country = country + self.kwargs['country'] = country + qs = qs.filter(country=country) + + if city_slug: + city = get_object_or_404(City, url=city_slug) + self.city = city + self.kwargs['city'] = city + qs = qs.filter(city=city) + self.filter_object = theme return qs + def get_context_data(self, **kwargs): + context = super(ExpoThemeCatalog, self).get_context_data(**kwargs) + if self.country: + context['country'] = self.country + if self.city: + context['city'] = self.city + context['theme_for_filter'] = self.kwargs['theme'] + return context + class ExpoTagCatalog(ExpoCatalog): catalog_url = '/expo/tag/' @@ -346,12 +407,13 @@ class ExpoTagCatalog(ExpoCatalog): #this method used in parent get_queryset slug = self.kwargs.get('slug') tag = get_object_or_404(Tag, url=slug) - qs = self.model.enable.filter(tag=tag) + self.kwargs['tag'] = tag + qs = self.model.enable.upcoming().filter(tag=tag) self.filter_object = tag return qs -class ExpoVisitors(ListView): +class ExpoVisitors(MetadataMixin, ListView): paginate_by = settings.CLIENT_PAGINATION model = Exposition #template_name = 'event_visitors.html' @@ -365,6 +427,7 @@ class ExpoVisitors(ListView): slug = self.kwargs.get('slug') exposition = get_object_or_404(self.model, url=slug) self.obj = exposition + self.object = self.obj return exposition.users.all() def get_context_data(self, **kwargs): @@ -374,7 +437,7 @@ class ExpoVisitors(ListView): return context -class ExpoMembers(ListView): +class ExpoMembers(MetadataMixin, ListView): paginate_by = settings.CLIENT_PAGINATION model = Exposition #template_name = 'event_visitors.html' @@ -388,6 +451,7 @@ class ExpoMembers(ListView): slug = self.kwargs.get('slug') exposition = get_object_or_404(self.model, url=slug) self.obj = exposition + self.object = self.obj return exposition.company.all() def get_context_data(self, **kwargs): diff --git a/file/forms.py b/file/forms.py index 8816ec37..ca57fc51 100644 --- a/file/forms.py +++ b/file/forms.py @@ -17,8 +17,8 @@ import pytils, re class FileForm(forms.Form): file_path = forms.FileField(label='Выберите файл') model = forms.CharField(required=False, widget=forms.HiddenInput()) - purposes = [('scheme teritory','Схема територии'),('preview','Превью')] - purpose = forms.ChoiceField(label='Назаначение', choices=purposes) + purposes = [('scheme teritory','Схема территории'),('preview','Превью'), ('preview2','Превью2')] + purpose = forms.ChoiceField(label='Назначение', choices=purposes) def __init__(self, *args, **kwargs): """ diff --git a/file/models.py b/file/models.py index 19eba496..c166a0a8 100644 --- a/file/models.py +++ b/file/models.py @@ -20,7 +20,8 @@ PURPOSES = (('photo', 'Фото'), ('map','Карта'), ('scheme teritory','Схема територии'), ('diplom','Дипломы'), - ('preview','Превью') + ('preview','Превью'), + ('preview2','Превью'), ) class FileModel(TranslatableModel): diff --git a/functions/admin_forms.py b/functions/admin_forms.py index e1a78da9..d63db3f5 100644 --- a/functions/admin_forms.py +++ b/functions/admin_forms.py @@ -44,6 +44,6 @@ class AdminFilterForm(forms.Form): qs = model.objects.all() if name: - qs = qs.filter(translations__name__contains=name).distinct() + qs = qs.filter(translations__name__icontains=name).distinct() return qs \ No newline at end of file diff --git a/functions/admin_views.py b/functions/admin_views.py index 5a0f1802..0fb38183 100644 --- a/functions/admin_views.py +++ b/functions/admin_views.py @@ -25,6 +25,11 @@ class AdminView(FormView): obj = get_object_or_404(self.model, slug=slug) self.obj = obj return obj + id = self.kwargs.get('id') + if id: + obj = get_object_or_404(self.model, id=id) + self.obj = obj + return obj self.obj = None return None diff --git a/functions/cache_mixin.py b/functions/cache_mixin.py new file mode 100644 index 00000000..9e8474f2 --- /dev/null +++ b/functions/cache_mixin.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +import random +from django.contrib.auth.decorators import login_required +from django.utils.cache import patch_response_headers +from django.utils.decorators import method_decorator +from django.views.decorators.cache import cache_page, never_cache +from django.views.decorators.csrf import csrf_exempt + +class NeverCacheMixin(object): + @method_decorator(never_cache) + def dispatch(self, *args, **kwargs): + return super(NeverCacheMixin, self).dispatch(*args, **kwargs) + + +class LoginRequiredMixin(object): + @method_decorator(login_required) + def dispatch(self, *args, **kwargs): + return super(LoginRequiredMixin, self).dispatch(*args, **kwargs) + + +class CacheMixin(object): + cache_timeout = 60 + + def get_cache_timeout(self): + return self.cache_timeout + + def dispatch(self, *args, **kwargs): + return cache_page(self.get_cache_timeout())(super(CacheMixin, self).dispatch)(*args, **kwargs) + + +class CacheControlMixin(object): + cache_timeout = 60 + + def get_cache_timeout(self): + return self.cache_timeout + + def dispatch(self, *args, **kwargs): + response = super(CacheControlMixin, self).dispatch(*args, **kwargs) + patch_response_headers(response, self.get_cache_timeout()) + return response + + +class JitterCacheMixin(CacheControlMixin): + cache_range = [60, 120] + + def get_cache_range(self): + return self.cache_range + + def get_cache_timeout(self): + return random.randint(*self.get_cache_range()) \ No newline at end of file diff --git a/functions/custom_views.py b/functions/custom_views.py index cce1e3f4..dfbc9071 100644 --- a/functions/custom_views.py +++ b/functions/custom_views.py @@ -227,7 +227,7 @@ class ExpoListView(ExpoMixin, ListView): """ """ - paginate_by = 10 + paginate_by = settings.CLIENT_PAGINATION params = None single_page = False search_form = None @@ -320,17 +320,16 @@ class EventDetail(ExpoMixin, DetailView): from haystack.query import EmptySearchQuerySet class ExpoSearchView(ListView): - paginate_by = 10 + paginate_by = settings.CLIENT_PAGINATION template_name = None search_form = None model = None - def get_queryset(self): + def get_queryset(self): if self.request.GET: form = self.search_form(self.request.GET) if form.is_valid(): - return form.search() else: return EmptySearchQuerySet() @@ -340,10 +339,13 @@ class ExpoSearchView(ListView): def get_context_data(self, **kwargs): context = super(ExpoSearchView, self).get_context_data(**kwargs) - form = self.search_form(self.request.GET) + if self.request.GET: + form = self.search_form(self.request.GET) if form.is_valid(): form.data_with_parents = form.get_form_data() + else: + form = self.search_form() context['search_form'] = form @@ -352,4 +354,5 @@ class ExpoSearchView(ListView): del queries['page'] context['queries'] = queries + return context \ No newline at end of file diff --git a/functions/form_check.py b/functions/form_check.py index 61c7cab3..e8c0954e 100644 --- a/functions/form_check.py +++ b/functions/form_check.py @@ -20,7 +20,7 @@ from slugify import slugify def translit_with_separator(string, separator='-'): - return slugify(string, to_lower=True) + #return slugify(string) """ Trsanslit string and replace "bad" symbols for separator diff --git a/functions/model_mixin.py b/functions/model_mixin.py index 7f5950c6..36b120b4 100644 --- a/functions/model_mixin.py +++ b/functions/model_mixin.py @@ -77,8 +77,9 @@ class EventMixin(object): def get_services(self): - ids = [item for item, bool in self.country.services if bool==True] - ##sasa + country_ids = [item for item, bool in self.country.services if bool==True] + ids = [item for item, bool in self.services if bool==True and item in country_ids] + return list(Service.objects.language().filter(url__in=ids).order_by('sort')) def duration_days(self, month=None): diff --git a/functions/models_methods.py b/functions/models_methods.py index 4edde8d0..486fb71e 100644 --- a/functions/models_methods.py +++ b/functions/models_methods.py @@ -1,7 +1,17 @@ +import datetime from django.utils.translation import get_language +from django.db.models import Q +from django.core.cache import cache +from django.utils import translation from hvad.models import TranslationManager + class ExpoManager(TranslationManager): + + def upcoming(self): + return self.language().select_related('country', 'city', 'place').filter(data_begin__gte=datetime.datetime.now().date()).order_by('data_begin') + + def all(self, lang=None): if lang: return super(ExpoManager, self).language(lang).all().order_by('name') @@ -16,6 +26,110 @@ class ExpoManager(TranslationManager): return None +class CityManager(TranslationManager): + cache_time = 600 + def all(self): + lang = get_language() + qs = super(CityManager, self).select_related('exposition_city', 'conference_city') + qs = qs.filter(Q(exposition_city__city__isnull=False) | Q(conference_city__city__isnull=False))\ + .order_by('translations__name').distinct() + + return qs + + def active_qs(self): + from exposition.models import Exposition + cities_id = [item['city_id'] for item in Exposition.objects.values('city_id').distinct()] + return self.language().filter(id__in=cities_id) + + def expo_cities(self): + lang = translation.get_language() + key = 'used_expo_cities_%s'%lang + cached_cities = cache.get(key) + if cached_cities: + return cached_cities + else: + from exposition.models import Exposition + cities_id = [item['city_id'] for item in Exposition.objects.values('city_id').distinct()] + cities = list(self.language().filter(id__in=cities_id)) + cache.set(key, cities, self.cache_time) + return cities + + def expo_cities_with_count(self): + lang = translation.get_language() + key = 'used_expo_cities_count_%s'%lang + cached_cities = cache.get(key) + if cached_cities: + return cached_cities + else: + + from exposition.models import Exposition + sql = {'expo_count': + """SELECT COUNT(*) + FROM exposition_exposition + WHERE exposition_exposition.city_id = city_city.id + AND exposition_exposition.data_end >= CURDATE() + AND exposition_exposition.is_published = 1"""} + now = datetime.datetime.now().date() + # id of unique cities + cities_id = [item['city_id'] for item in Exposition.objects.filter(is_published=True, data_end__gte=now).values('city_id').distinct()] + cities = set(list(self.language().filter(id__in=cities_id).extra(select=sql))) + cities = sorted(cities, key=lambda x: x.name) + cache.set(key, cities, self.cache_time) + return cities + + def conference_cities_with_count(self): + lang = translation.get_language() + key = 'used_conference_cities_count_%s'%lang + cached_cities = cache.get(key) + if cached_cities: + return cached_cities + else: + + from conference.models import Conference + sql = {'conference_count': + """SELECT COUNT(*) + FROM conference_conference + WHERE conference_conference.city_id = city_city.id + AND conference_conference.data_end >= CURDATE() + AND conference_conference.is_published = 1"""} + now = datetime.datetime.now().date() + # id of unique countries + cities_id = [item['city_id'] for item in Conference.objects.filter(is_published=True, data_end__gte=now).values('city_id').distinct()] + cities = set(list(self.language().filter(id__in=cities_id).extra(select=sql))) + cities = sorted(cities, key=lambda x: x.name) + cache.set(key, cities, self.cache_time) + return cities + + + def conference_cities(self): + lang = translation.get_language() + key = 'used_conference_cities_%s'%lang + cached_cities = cache.get(key) + if cached_cities: + return cached_cities + else: + from conference.models import Conference + cities_id = [item['city_id'] for item in Conference.objects.values('city_id').distinct()] + cities = list(self.language().filter(id__in=cities_id)) + cache.set(key, cities, self.cache_time) + return cities + + def cities(self): + """ + not finished + """ + lang = translation.get_language() + key = 'used_cities_%s'%lang + cached_cities = cache.get(key) + if cached_cities: + return cached_cities + else: + from exposition.models import Exposition + cities_id = [item['city_id'] for item in Exposition.objects.values('city_id').distinct()] + cities = list(self.language().filter(id__in=cities_id)) + cache.set(key, cities, self.cache_time) + return cities + def hvad_to_dict(object): """ diff --git a/functions/search_forms.py b/functions/search_forms.py index ed0c58e8..d24eb185 100644 --- a/functions/search_forms.py +++ b/functions/search_forms.py @@ -22,7 +22,7 @@ from place_conference.models import PlaceConference class AbstactSearchForm(forms.Form): - q = forms.CharField(label=_(u'Я ищу'), required=False) + q = forms.CharField(label=_(u'Я ищу'), required=False, widget=forms.TextInput(attrs={'placeholder':_(u'Тематика, слово или название')})) w = forms.CharField(label=_(u'Где'), required=False) models = None data_with_parents = None @@ -99,6 +99,8 @@ class AbstactSearchForm(forms.Form): return result + + def get_places_display(self): if self.is_valid(): area = self.cleaned_data['area'] @@ -219,11 +221,7 @@ class AbstactSearchForm(forms.Form): sqs = sqs.filter(place_filter) return sqs#.order_by('data_begin') - - - - - +import datetime class ExpositionSearchForm(AbstactSearchForm): search_url = '/expo/search/' autocomplete_url = '/search-form/autosearch/exposition/' @@ -236,24 +234,21 @@ class ExpositionSearchForm(AbstactSearchForm): #co = forms.CharField(label=_(u'Страна'), required=False, widget=forms.CheckboxSelectMultiple()) #tg = forms.CharField(label=_(u'Теги'), required=False, widget=forms.CheckboxSelectMultiple()) - area = forms.MultipleChoiceField(label=_(u'Регион'), choices=[(item.id, item.name) for item in Area.objects.all_sorted()], + area = forms.MultipleChoiceField(label=_(u'Регион'), + choices=[(item.id, item.name) for item in Area.objects.language().all()], required=False, widget=forms.CheckboxSelectMultiple()) co = forms.MultipleChoiceField(label=_(u'Страна'), required=False, widget=forms.CheckboxSelectMultiple(), - choices=[(item.id, item.name) for item in Country.objects.select_related('exposition_country')\ - .filter(exposition_country__country__isnull=False, translations__language_code=translation.get_language())\ - .order_by('translations__name').distinct()] + choices=[(item.id, item.name) for item in Country.objects.expo_countries()] ) ci = forms.MultipleChoiceField(label=_(u'Город'), required=False, widget=forms.CheckboxSelectMultiple(), - choices=[(item.id, item.name) for item in City.objects.select_related('exposition_city')\ - .filter(exposition_city__city__isnull=False, translations__language_code=translation.get_language())\ - .order_by('translations__name').distinct()] + choices=[(item.id, item.name) for item in City.used.expo_cities()] ) - fr = forms.DateField(required=False, + fr = forms.DateField(required=False, input_formats=('%d.%m.%Y',), widget=forms.DateInput(attrs={'class': 'date', 'id': 'dateFrom', 'placeholder': _(u'дд.мм.гггг')})) - to = forms.DateField(required=False, + to = forms.DateField(required=False, input_formats=('%d.%m.%Y',), widget=forms.DateInput(attrs={'class': 'date', 'id': 'dateTo', 'placeholder': _(u'дд.мм.гггг')})) @@ -269,6 +264,8 @@ class ExpositionSearchForm(AbstactSearchForm): q = self.cleaned_data.get('q') w = self.cleaned_data.get('w') fr = self.cleaned_data.get('fr') + if not fr: + fr = datetime.date.today() to = self.cleaned_data.get('to') th = self.cleaned_data.get('th') tg = self.cleaned_data.get('tg') @@ -276,6 +273,7 @@ class ExpositionSearchForm(AbstactSearchForm): ci = self.cleaned_data.get('ci') area = self.cleaned_data.get('area') + sqs = SearchQuerySet().models(Exposition).all() if q: @@ -325,18 +323,14 @@ class PlaceSearchForm(AbstactSearchForm): title = _(u'ПОИСК МЕСТ') models = [PlaceExposition, PlaceConference] # place fields - area = forms.MultipleChoiceField(label=_(u'Регион'), choices=[(item.id, item.name) for item in Area.objects.all_sorted()], + area = forms.MultipleChoiceField(label=_(u'Регион'), choices=[(item.id, item.name) for item in list(Area.objects.language().all())], required=False, widget=forms.CheckboxSelectMultiple()) co = forms.MultipleChoiceField(label=_(u'Страна'), required=False, widget=forms.CheckboxSelectMultiple(), - choices=[(item.id, item.name) for item in Country.objects.select_related('exposition_country')\ - .filter(exposition_country__country__isnull=False, translations__language_code=translation.get_language())\ - .order_by('translations__name').distinct()] + choices=[(item.id, item.name) for item in list(Country.objects.expo_countries())] ) ci = forms.MultipleChoiceField(label=_(u'Город'), required=False, widget=forms.CheckboxSelectMultiple(), - choices=[(item.id, item.name) for item in City.objects.select_related('exposition_city')\ - .filter(exposition_city__city__isnull=False, translations__language_code=translation.get_language())\ - .order_by('translations__name').distinct()] + choices=[(item.id, item.name) for item in list(City.used.expo_cities())] ) # place_type = forms.MultipleChoiceField(label=_(u'Тип'), required=False, choices=[]) @@ -356,23 +350,19 @@ class CompanySearchForm(AbstactSearchForm): required=False, widget=forms.CheckboxSelectMultiple()) tg = forms.CharField(label=_(u'Теги'), required=False, widget=forms.CheckboxSelectMultiple()) - area = forms.MultipleChoiceField(label=_(u'Регион'), choices=[(item.id, item.name) for item in Area.objects.all_sorted()], + area = forms.MultipleChoiceField(label=_(u'Регион'), choices=[(item.id, item.name) for item in Area.objects.language().all()], required=False, widget=forms.CheckboxSelectMultiple()) co = forms.MultipleChoiceField(label=_(u'Страна'), required=False, widget=forms.CheckboxSelectMultiple(), - choices=[(item.id, item.name) for item in Country.objects.select_related('exposition_country')\ - .filter(exposition_country__country__isnull=False, translations__language_code=translation.get_language())\ - .order_by('translations__name').distinct()] + choices=[(item.id, item.name) for item in Country.objects.expo_countries()] ) ci = forms.MultipleChoiceField(label=_(u'Город'), required=False, widget=forms.CheckboxSelectMultiple(), - choices=[(item.id, item.name) for item in City.objects.select_related('exposition_city')\ - .filter(exposition_city__city__isnull=False, translations__language_code=translation.get_language())\ - .order_by('translations__name').distinct()] + choices=[(item.id, item.name) for item in City.used.expo_cities()] ) def __init__(self, *args, **kwargs): super(CompanySearchForm, self).__init__(*args, **kwargs) - self.theme_classes = {item.id:item.generate_search_class() for item in Theme.objects.all()} + self.theme_classes = {item.id:item.generate_search_class() for item in list(Theme.objects.language().all())} def search(self): q = self.cleaned_data.get('q') @@ -431,4 +421,5 @@ class EventSearchForm(forms.Form): if w: sqs = sqs.filter(where__contains=w) - return sqs \ No newline at end of file + return sqs + diff --git a/functions/signal_handlers.py b/functions/signal_handlers.py index d2a49d65..3a37aef1 100644 --- a/functions/signal_handlers.py +++ b/functions/signal_handlers.py @@ -6,7 +6,7 @@ from functions.form_check import translit_with_separator def pre_save_handler(sender, **kwargs): obj = kwargs['instance'] - if obj.language_code =='en': + if hasattr(obj, 'language_code') and obj.language_code =='en': try: name = getattr(obj, 'name') obj.url = translit_with_separator(name) diff --git a/functions/translate.py b/functions/translate.py index c1a154a2..a2d1a16f 100644 --- a/functions/translate.py +++ b/functions/translate.py @@ -101,20 +101,27 @@ def fill_with_signal(model, obj, data): # translated fields fields = [field.name for field in model.translations.related.editable_fields() if field.name not in bad_fields] + # translate to first language(require) # ! first save method call signal that fill require language to all translated fields if not obj.id: # new object obj.translate(all_langs[0]) # go through all fields and set value + for field in fields: - setattr(obj, field, data.get('%s_%s'%(field, all_langs[0])).strip()) + value = data.get('%s_%s'%(field, all_langs[0]), '') + if value: + setattr(obj, field, value.strip()) obj.save() else: trans_obj = model._meta.translations_model.objects.get(language_code = all_langs[0], master__id=getattr(obj, 'id')) for field in fields: - setattr(trans_obj, field, data.get('%s_%s'%(field, all_langs[0])).strip()) + + value = data.get('%s_%s'%(field, all_langs[0]), '') + if value: + setattr(trans_obj, field, value.strip()) trans_obj.save() @@ -126,7 +133,7 @@ def fill_with_signal(model, obj, data): # start from second language trans_obj = model._meta.translations_model.objects.get(language_code = code,master__id=getattr(obj, 'id')) for field in fields: - val = data.get('%s_%s'%(field, code)).strip() + val = data.get('%s_%s'%(field, code), '').strip() if val == '': # get value from require translation setattr(trans_obj, field, getattr(require_transl, field)) diff --git a/import_xls/admin.py b/import_xls/admin.py index 00ebe370..a2b43cc3 100644 --- a/import_xls/admin.py +++ b/import_xls/admin.py @@ -11,7 +11,8 @@ import xlrd from import_forms import ImportEventForm, ImportThemeForm, ImportTagForm, ImportOrganiserForm,\ ImportPlaceConferenceForm, ImportPlaceExpositionForm from export_forms import ExportEventForm, ExportOrganiserForm, ExportThemeForm, ExportTagForm,\ - ExportUserForm, ExportCompanyForm, ExportPlaceConferenceForm, ExportPlaceExpositionForm + ExportUserForm, ExportCompanyForm, ExportPlaceConferenceForm, ExportPlaceExpositionForm, ExportBlogForm,\ + ExportCityForm from django.views.generic import FormView from django.contrib import messages @@ -78,6 +79,18 @@ class ExportPlaceExposition(ExportView): form_class = ExportPlaceExpositionForm success_url = '/admin/export-place_exposition' +class ExportBlog(ExportView): + form_class = ExportBlogForm + success_url = '/admin/export-blog/' + +class ExportBlog(ExportView): + form_class = ExportBlogForm + success_url = '/admin/export-blog/' + +class ExportCity(ExportView): + form_class = ExportCityForm + success_url = '/admin/export-city/' + from exposition.models import Exposition diff --git a/import_xls/admin_urls.py b/import_xls/admin_urls.py index d96f53de..baf65303 100644 --- a/import_xls/admin_urls.py +++ b/import_xls/admin_urls.py @@ -3,7 +3,7 @@ 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 + ExportPlaceConference, ExportCompany, ExportUser, ExportBlog, ExportCity urlpatterns = patterns('', url(r'^import-event/$', ImportEvent.as_view()), @@ -21,5 +21,7 @@ urlpatterns = patterns('', url(r'^export-place_conference/$', ExportPlaceConference.as_view()), url(r'^export-user/$', ExportUser.as_view()), url(r'^export-company/$', ExportCompany.as_view()), + url(r'^export-blog/$', ExportBlog.as_view()), + url(r'^export-city/$', ExportCity.as_view()), ) diff --git a/import_xls/excel_settings.py b/import_xls/excel_settings.py index a6f19251..e86715eb 100644 --- a/import_xls/excel_settings.py +++ b/import_xls/excel_settings.py @@ -247,7 +247,6 @@ def to_phone(value): value = value.replace(elem, '') value = to_int(value) - print(value) return value @@ -279,9 +278,16 @@ def save_halls(obj, value): name = l[0].strip() res.append({'area': area, 'name':name, 'number': number}) + Hall.objects.filter(place_exposition=obj).delete() for hall in res: h = Hall(place_exposition = obj, name=hall.get('name'), number=hall.get('number'), capacity=hall.get('area')) - h.save() + try: + h.save() + except Exception, e: + print('---------------hall error---------') + print e + print('---------------------------------') + place_exp_sett = { u'ID':{u'field': u'id', u'func': to_int}, @@ -295,7 +301,7 @@ place_exp_sett = { u'Тел.':{u'field': u'phone', u'func': to_phone}, u'Факс':{u'field': u'fax', u'func': to_phone}, u'Фото':{u'field': u'photo', u'func': save_photo, u'method': True}, - u'Лого':{u'field': u'logo', u'func': save_file, u'method': True, u'purpose': 'logo'}, + u'Лого':{u'field': u'logo', u'func': save_logo, u'method': True}, u'Веб-сайт':{u'field': u'web_page', u'func': unicode}, u'Email':{u'field': u'email', u'func': unicode}, u'Карта проезда':{u'field': u'map', u'func': save_file, u'method': True, u'purpose': 'map'}, @@ -324,6 +330,17 @@ place_exp_sett = { u'Мобильное приложение':{u'field': u'mobile_application', u'func': bool}, } + + + +article_sett = { + u'ID':{u'field': u'id', u'func': to_int}, + u'Заголовок':{u'field': u'main_title', u'func': unicode}, + u'Описание':{u'field': u'description', u'func': unicode}, + u'Айди автора':{u'field': u'author', u'func': to_user}, + u'Создана':{u'field': u'created', u'func': to_datetime} +} + event_sett = { u'ID':{u'field': u'id', u'func': to_int}, u'Url':{u'field': u'url', u'func': unicode}, @@ -332,16 +349,19 @@ event_sett = { u'Дата начала:(YYYY-MM-DD)':{u'field': u'data_begin', u'func': to_date}, u'Дата окончания:(YYYY-MM-DD)':{u'field': u'data_end', u'func': to_date}, u'Страна':{u'field': u'country', u'func': to_country}, - u'Город':{u'field': u'city', u'func': to_city, 'extra_values': 'country'}, - u'Место проведения':{u'field': u'place', u'func': to_place}, + u'Город':{u'field': u'city_id', u'func': to_city, 'extra_values': 'country'}, + #u'Место проведения':{u'field': u'place', u'func': to_place}, u'ID Тематики':{u'field': u'theme', u'func': to_theme, u'method': True},### u'Теги':{u'field': u'tag', u'func': to_tag, u'method': True}, #u'Организатор №1':{u'field': u'organiser', u'func': to_tag},#### #u'Организатор №2':{u'field': u'organiser', u'func': to_tag},#### u'Описание события':{u'field': u'description', u'func': unicode}, + u'Основные темы':{u'field': u'main_themes', u'func': unicode}, + u'Условия и скидка':{u'field': u'discount_description', u'func': unicode}, u'Периодичность':{u'field': u'periodic', u'func': to_periodic},### u'Аудитория':{u'field': u'audience', u'func': to_audience}, u'Официальный веб-сайт':{u'field': u'web_page', u'func': to_url}, + u'Линк на регистрацию':{u'field': u'link', u'func': to_url}, u'Экспонируемые продукты':{u'field': u'products', u'func': unicode}, u'Время работы':{u'field': u'time', u'func': unicode}, u'Логотип':{u'field': u'logo', u'func': save_logo, u'method': True}, @@ -366,7 +386,7 @@ event_sett = { u'Min_Pack кв.м.':{u'field': u'min_closed_equipped_area', u'func': to_int}, u'Max_Pack кв.м.':{u'field': u'max_closed_equipped_area', u'func': to_int}, u'Открытая площадь':{u'field': u'max_open_area', u'func': to_int}, - u'Мин. Площадь кв.м.':{u'field': u'min_open_area', u'func': to_int}, + u'Мин. Площадь кв.м.':{u'field': u'min_stand_size', u'func': to_int}, u'Регистрационный взнос':{u'field': u'registration_payment', u'func': to_int}, u'Примечание по участии':{u'field': u'participation_note', u'func': unicode}, u'Крайний срок подачи заявки':{u'field': u'application_deadline', u'func': to_date}, diff --git a/import_xls/export_forms.py b/import_xls/export_forms.py index 28470ff9..6964194b 100644 --- a/import_xls/export_forms.py +++ b/import_xls/export_forms.py @@ -1,11 +1,14 @@ # -*- coding: utf-8 -*- from django import forms from django.conf import settings +from django.utils import translation from theme.models import Theme, Tag from country.models import Country +from city.models import City from organiser.models import Organiser from accounts.models import User from company.models import Company +from article.models import Article from place_exposition.models import PlaceExposition from place_conference.models import PlaceConference from django.db.models.loading import get_model @@ -149,6 +152,25 @@ class ExportCompanyForm(ExportForm): def get_fname(self): return 'companies.xls' +class ExportBlogForm(ExportForm): + model = Article + + def get_fname(self): + return 'blogs.xls' + + def get_objects(self, data): + translation.activate(data['language']) + return self.model.objects.blogs() + +class ExportCityForm(ExportForm): + model = City + + def get_fname(self): + return 'cities.xls' + + def get_objects(self, data): + translation.activate(data['language']) + return self.model.used.all() class ExportEventForm(forms.Form): diff --git a/import_xls/utils.py b/import_xls/utils.py index 0cf02daa..904b69d4 100644 --- a/import_xls/utils.py +++ b/import_xls/utils.py @@ -12,6 +12,7 @@ from city.models import City from theme.models import Theme, Tag from functions.files import get_alternative_filename from exposition.models import BIT_AUDIENCE +from accounts.models import User def to_int(val): @@ -29,19 +30,32 @@ def to_date(value): return None if isinstance(value, unicode) or isinstance(value, str): - - t = time.strptime(value, "%d.%m.%Y") + try: + t = time.strptime(value, "%d.%m.%Y") + except ValueError: + t = time.strptime(value, "%d/%m/%Y") if isinstance(value, float): t = xlrd.xldate_as_tuple(value, 0)+(0,0,0) + return time.strftime("%Y-%m-%d", t) +def to_datetime(value): + if not value: + return None + if isinstance(value, unicode) or isinstance(value, str): + t = time.strptime(value, "%Y-%m-%d %H:%M:%S") + return time.strftime("%Y-%m-%d %H:%M:%S", t) + + def to_country(value): try: query = get_translation_aware_manager(Country) country = query.filter(name=value)[0] return country except IndexError: + print('---------------------') print(value.encode('utf8')) + print('AAAAAAAA') return None def to_city(value, lang, country): @@ -51,9 +65,9 @@ def to_city(value, lang, country): # except IndexError if no found city = City.objects.filter(translations__name=value, country=country)[0] # print(city) - return city + return city.id except IndexError: - print('---------------------') + print('---------city error------------') print(value.encode('utf8')) print('---------------------') return None @@ -70,6 +84,9 @@ def to_theme(obj, value): else: theme_ids = value.split(',') + if theme_ids == ['']: + return + obj.theme.clear() obj.theme.add(*Theme.objects.filter(id__in=theme_ids)) def to_tag(obj,value): @@ -78,6 +95,7 @@ def to_tag(obj,value): names = value.split(',') translation.activate('en') if names: + obj.tag.clear() obj.tag.add(*Tag.objects.filter(translations__name__in=names, theme__in=obj.theme.all())) else: return @@ -140,16 +158,23 @@ def save_logo(obj, path): logo_path = obj.logo.field.upload_to full_path = settings.MEDIA_ROOT + logo_path - - alt_name = get_alternative_filename(full_path, file_name) + try: + alt_name = get_alternative_filename(full_path, file_name) + except UnicodeEncodeError: + return None download_to = full_path+alt_name if path.startswith('http://') or path.startswith('https://'): url = path - else: + elif path.startswith('/'): + url = 'http://expomap.ru' + path + elif path.startswith('images'): + url = 'http://expomap.ru/' + path + else: + return None try: response = urllib2.urlopen(url, timeout=15) @@ -181,4 +206,11 @@ def check_quality_label(obj, value, label): return bit if value: setattr(bit, label, True) - return bit \ No newline at end of file + return bit + +def to_user(value): + try: + return User.objects.get(id=value) + except User.DoesNotExist: + + return User.objects.get(id=1) \ No newline at end of file diff --git a/meta/admin.py b/meta/admin.py new file mode 100644 index 00000000..5d944cd3 --- /dev/null +++ b/meta/admin.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +from django.shortcuts import render_to_response +from django.http import HttpResponseRedirect, HttpResponse +from django.core.context_processors import csrf +from django.conf import settings +from django.forms.formsets import BaseFormSet, formset_factory +from django.forms.models import modelformset_factory +from django.contrib.contenttypes.models import ContentType +from django.contrib.auth.decorators import login_required +#models and forms +from models import MetaSetting +from forms import MetaForm, MetaFilterForm +from functions.admin_views import AdminListView, AdminView + + + +class MetaListView(AdminListView): + template_name = 'admin/meta/meta_list.html' + form_class = MetaFilterForm + model = MetaSetting + +class MetaView(AdminView): + form_class = MetaForm + model = MetaSetting + success_url = '/admin/meta/all/' + template_name = 'admin/meta/meta_setting.html' + + def form_valid(self, form): + self.set_obj() + expo = form.save(obj=self.obj) + + return HttpResponseRedirect(self.success_url) + + def get_form(self, form_class): + if self.request.POST: + return super(MetaView, self).get_form(form_class) + obj = self.set_obj() + if obj: + data = {'name':obj.name} + + for code, name in settings.LANGUAGES: + trans_obj = self.model._meta.translations_model.objects.get(language_code = code,master__id=obj.id) #access to translated fields + data['title_%s' % code] = trans_obj.title + data['description_%s' % code] = trans_obj.description + data['keywords_%s' % code] = trans_obj.keywords + data['h1_%s' % code] = trans_obj.h1 + + form =form_class(initial=data) + return form + else: + return form_class() + + + def get_context_data(self, **kwargs): + context = super(MetaView, self).get_context_data(**kwargs) + obj = self.set_obj() + return context \ No newline at end of file diff --git a/meta/admin_urls.py b/meta/admin_urls.py new file mode 100644 index 00000000..f2062f38 --- /dev/null +++ b/meta/admin_urls.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +from django.conf.urls import patterns, include, url +from admin import MetaListView, MetaView + +urlpatterns = patterns('conference.admin', + + url(r'^all/$', MetaListView.as_view()), + #url(r'^change/(?P.*)/$', 'conference_change'), + url(r'^(?P.*)/$', MetaView.as_view()), + url(r'^$', MetaView.as_view()), +) \ No newline at end of file diff --git a/meta/decorators.py b/meta/decorators.py new file mode 100644 index 00000000..b0b3bcbf --- /dev/null +++ b/meta/decorators.py @@ -0,0 +1,23 @@ +from meta.views import Meta + +def add_meta(view): + def wrapper(request, *args, **kwargs): + """ + meta = Meta( + title=title, + description=description, + keywords=keywords, + meta_extras = { + 'viewport': 'width=device-width, initial-scale=1.0, minimum-scale=1.0' + } + 'extra_custom_props': [ + ('http-equiv', 'Content-Type', 'text/html; charset=UTF-8'), + ] + ) + """ + + + r = view(request, *args, **kwargs) + r.context_data = {'foo': 'bar'} + return r.render() + return wrapper \ No newline at end of file diff --git a/meta/forms.py b/meta/forms.py new file mode 100644 index 00000000..ee8983cc --- /dev/null +++ b/meta/forms.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +from django import forms +from django.conf import settings +from models import MetaSetting +from functions.translate import fill_with_signal +from functions.admin_forms import AdminFilterForm + + +class MetaForm(forms.Form): + name = forms.CharField(label=u'Название страницы') + + def __init__(self, *args, **kwargs): + """ + create dynamical translated fields fields + """ + super(MetaForm, self).__init__(*args, **kwargs) + #creates translated forms example: name_ru, name_en + # len(10) is a hack for detect if settings.LANGUAGES is not configured it return all langs + if len(settings.LANGUAGES) in range(10): + for lid, (code, name) in enumerate(settings.LANGUAGES): + # uses enumerate for detect iteration number + # first iteration is a default lang so it required fields + required = True if lid == 0 else False + self.fields['title_%s' % code] = forms.CharField(label=u'Title', required=required, + widget=forms.TextInput(attrs={'style':'width: 550px'})) + self.fields['description_%s' % code] = forms.CharField(label=u'Description', required=required, + widget=forms.TextInput(attrs={'style':'width: 550px'})) + self.fields['keywords_%s' % code] = forms.CharField(label=u'Keywords', required=False, + widget=forms.TextInput(attrs={'style':'width: 550px'})) + self.fields['h1_%s' % code] = forms.CharField(label=u'H1', required=False, + widget=forms.TextInput(attrs={'style':'width: 550px'})) + + def save(self, obj=None): + data = self.cleaned_data + if not obj: + meta = MetaSetting() + else: + meta = obj + + meta.name = data['name'] + + + # fill translated fields and save object + fill_with_signal(MetaSetting, meta, data) + meta.save() + +class MetaFilterForm(AdminFilterForm): + model = MetaSetting \ No newline at end of file diff --git a/meta/models.py b/meta/models.py index 39f32f06..ede47701 100644 --- a/meta/models.py +++ b/meta/models.py @@ -1,8 +1,44 @@ # -*- coding: utf-8 -*- from django.db import models -from hvad.models import TranslatableModel, TranslatedFields, TranslationManager from django.utils import translation +from django.db.models.signals import post_save +from django.utils.translation import ugettext_lazy as _ +from hvad.models import TranslatableModel, TranslatedFields, TranslationManager from pymorphy.django_conf import default_morph as morph +from functions.signal_handlers import post_save_handler + +# additional funcs +MONTHES = {'jan': _(u'январе'), 'feb': _(u'феврале'), 'mar': _(u'марте'), 'apr': _(u'апреле'), + 'may': _(u'мае'), 'jun': _(u'июне'), u'jul': _(u'июле'), 'aug': _(u'августе'), + 'sep': _(u'сентябре'), 'oct': _(u'октябре'), 'nov': _(u'ноябре'), 'dec': _(u'декабре'),} +def get_month_inflect(value, key): + return {key: MONTHES.get(value, '') } + +def get_obj_inflect(obj, key): + if translation.get_language() == 'ru': + result = {key: getattr(obj, 'inflect', '')} + else: + result = {key: getattr(obj, 'name', '')} + return result + +def get_theme_inflect(obj, key): + if translation.get_language() == 'ru': + result = {'theme_inflect': getattr(obj, 'inflect', ''), + 'theme_name': getattr(obj, 'name', '')} + else: + result = {'theme_inflect': getattr(obj, 'name', ''), + 'theme_name': getattr(obj, 'name', '')} + return result + +def get_tag_inflect(obj, key): + if translation.get_language() == 'ru': + result = {'tag_inflect': getattr(obj, 'inflect', ''), + 'tag_name': getattr(obj, 'name', '')} + else: + result = {'tag_inflect': getattr(obj, 'name', ''), + 'tag_name': getattr(obj, 'name', '')} + return result + class MetaSetting(TranslatableModel): name = models.CharField(max_length=100, unique=True) @@ -13,32 +49,41 @@ class MetaSetting(TranslatableModel): h1 = models.CharField(max_length=255, blank=True), ) - params = {'EXPONAME':{'name': 'name'}, - 'EXPONAME_YA':{'name': 'name', 'inflect': True}, - 'EXPOCOUNTRY':{'name': 'country'}, - 'EXPOCOUNTRY_YA':{'name': 'country', 'inflect': True}, - 'EXPOPLACE':{'name': 'place'}, - 'EXPOCITY':{'name': 'city'}, - 'EXPOTHEME':{'name': 'theme'}, - 'EXPOTAG':{'name': 'tag'}, - 'EXPOMONTH':{'name': 'month'}, - 'EXPOYEAR':{'name': 'year'}, - } + object_params = {'object_name': 'name', 'object_title': 'main_title', 'city': 'city', 'country': 'country'} + + params = {'month': get_month_inflect, 'country': get_obj_inflect, 'city': get_obj_inflect, + 'theme': get_theme_inflect, 'tag': get_tag_inflect} + monthes = {'jan': _(u'январе'), 'feb': _(u'феврале'), 'mar': _(u'марте'), 'apr': _(u'апреле'), + 'may': _(u'мае'), 'jun': _(u'июне'), u'jul': _(u'июле'), 'aug': _(u'августе'), + 'sep': _(u'сентябре'), 'oct': _(u'октябре'), 'nov': _(u'ноябре'), 'dec': _(u'декабре'),} + def __unicode__(self): return self.name - def generate_meta(self, obj): + + def generate_meta(self, params, obj=None): """ obj must be in current language """ + lang = translation.get_language() - params = {'EXPONAME': getattr(obj, 'name', '')} + updates = {} + if obj: + for key, value in self.object_params.iteritems(): + updates.update({key: getattr(obj, value, '')}) + + for key, value in params.iteritems(): + if key in self.params: + updates.update(self.params[key](value, key)) + params.update(updates) + tr = self.translations.get(language_code=lang) title = tr.title.format(**params) description = tr.description.format(**params) keywords = []#tr.keywords.format(**params) h1 = tr.h1.format(**params) + return {'title': title, 'description': description, 'keywords': keywords, 'h1': h1} def get_param(self, obj, field): @@ -51,6 +96,21 @@ class MetaSetting(TranslatableModel): return s + def get_title(self): + title = self.title + return title + + def get_h1(self): + h1 = self.h1 + return h1 + + def get_description(self): + description = self.description + return description + def get_keywords(self): + keywords = self.keywords + return [] +post_save.connect(post_save_handler, sender=MetaSetting) \ No newline at end of file diff --git a/meta/views.py b/meta/views.py index f362194a..c8146091 100644 --- a/meta/views.py +++ b/meta/views.py @@ -1,6 +1,7 @@ from __future__ import unicode_literals from django.core.exceptions import ImproperlyConfigured +from models import MetaSetting from . import settings @@ -150,18 +151,40 @@ class MetadataMixin(object): return self.site_name or settings.SITE_NAME def get_context_data(self, **kwargs): + context = super(MetadataMixin, self).get_context_data(**kwargs) - context['meta'] = self.get_meta_class()( - use_og=self.use_og, - use_sites=self.use_sites, - title=self.get_meta_title(context=context), - h1=self.get_meta_h1(context=context), - - description=self.get_meta_description(context=context), - keywords=self.get_meta_keywords(context=context), - image=self.get_meta_image(context=context), - url=self.get_meta_url(context=context), - object_type=self.get_meta_object_type(context=context), - site_name=self.get_meta_site_name(context=context), - ) - return context + + meta_id = self.kwargs.get('meta_id') + if not meta_id: + meta_id = kwargs.get('meta_id') + + if meta_id: + try: + meta_set = MetaSetting.objects.language().get(id=meta_id) + except MetaSetting.DoesNotExist: + return context + params = dict(self.kwargs) + if getattr(self, 'object', None): + data = meta_set.generate_meta(params, self.object) + else: + data = meta_set.generate_meta(params) + + self.title = data.get('title') + self.h1 = data.get('h1') + self.description = data.get('description') + self.keywords = data.get('keywords', []) + + context['meta'] = self.get_meta_class()( + use_og=self.use_og, + use_sites=self.use_sites, + title=self.get_meta_title(context=context), + h1=self.get_meta_h1(context=context), + description=self.get_meta_description(context=context), + keywords=self.get_meta_keywords(context=context), + image=self.get_meta_image(context=context), + url=self.get_meta_url(context=context), + object_type=self.get_meta_object_type(context=context), + site_name=self.get_meta_site_name(context=context), + ) + + return context \ No newline at end of file diff --git a/organiser/management/commands/organiser_from_old_db.py b/organiser/management/commands/organiser_from_old_db.py index ce0e2b19..43bdeb32 100644 --- a/organiser/management/commands/organiser_from_old_db.py +++ b/organiser/management/commands/organiser_from_old_db.py @@ -1,7 +1,9 @@ +# -*- coding: utf-8 -*- from django.core.management.base import BaseCommand, CommandError from organiser.models import Organiser from theme.models import Theme, Tag from functions.form_check import translit_with_separator +from accounts.models import User import MySQLdb from MySQLdb.cursors import DictCursor @@ -21,9 +23,9 @@ def convert_to_int(st): class Command(BaseCommand): def handle(self, *args, **options): db = MySQLdb.connect(host="localhost", - user="root", + user="kotzilla", passwd="qazedc", - db="expomap_ru", + db="old_expomap", charset='utf8', cursorclass=DictCursor) @@ -31,18 +33,18 @@ class Command(BaseCommand): - sql = """SELECT DISTINCT(customers_company) as name, specialize, otrasly as theme, tags, adress, - phone, fax, email, website, twitter, about, customers_company.url + sql = """SELECT DISTINCT(customers_company) as name, customers_email_address as user_email, specialize, otrasly as theme, tags, adress, + phone, fax, email, website, twitter, about, customers_company.url, company_last_modified as modified FROM customers LEFT JOIN customers_company - ON customers.customers_company=customers_company.title + ON customers.customers_id = customers_company.customers_id WHERE customers_status = 4 """ cursor.execute(sql) res = cursor.fetchall() - + print(res[0].get('user_email')) for o in res: if not o.get('name'): @@ -66,7 +68,7 @@ class Command(BaseCommand): organiser.description = o.get('about') if organiser.name: - print('not_saved: %s'%o['name']) + print('not_saved: %s'%o['name'].encode('utf8')) organiser.save() print('saved: %s'%str(organiser)) @@ -75,12 +77,10 @@ class Command(BaseCommand): if theme_id: try: theme = Theme.objects.get(id=theme_id) + organiser.theme.add(theme) except Theme.DoesNotExist: - continue - organiser.theme.add(theme) + pass - if not theme: - continue tags = o.get('tags') if tags: @@ -104,5 +104,14 @@ class Command(BaseCommand): organiser.save() print(organiser) + user_email = o.get('user_email') + if user_email: + try: + user = User.objects.get(username=user_email) + user.organiser = organiser + user.save() + except User.DoesNotExist: + print('no user with this email: %s'%user_email) + print('success') diff --git a/organiser/models.py b/organiser/models.py index 8d09405b..ea4f748f 100644 --- a/organiser/models.py +++ b/organiser/models.py @@ -75,6 +75,7 @@ class Organiser(TranslatableModel): #fields saves information about creating and changing model created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) + active = models.NullBooleanField(default=0) def __unicode__(self): return self.lazy_translation_getter('name', self.pk) diff --git a/password_reset/templates/password_reset/recovery_email_expo.html b/password_reset/templates/password_reset/recovery_email_expo.html new file mode 100644 index 00000000..cfcca57d --- /dev/null +++ b/password_reset/templates/password_reset/recovery_email_expo.html @@ -0,0 +1,114 @@ + + + + + + + + + + + +
+ + + + + + +
+ + + + +
    +
  • RSS
  • +
  • Facebook
  • +
  • LinkedIn
  • +
  • В контакте
  • +
  • Twitter
  • +
+
+ + + + + + + + +

Воостановление пароля на портале Expomap

+ + + + + + + + + + + + + + + + + + + +
+

Добрый день, {{ user.first_name }}!

+
+ Вы или кто-то еще сделал запрос на сброс пароля на сайте {{ domain }} +
+ Вы можете восстановить доступ, нажав на кнопку ниже и указав новый пароль: +
+ востановить пароль +
+ Если вы не хотите сбрасывать пароль, просто проигнорируйте это сообщение +
+ + + +
+ + + + + + +
+ + + +
+ + + + +
+ © 2018 — 2013 Expomap.ru +
+ +
+ + \ No newline at end of file diff --git a/password_reset/views.py b/password_reset/views.py index 88b84a07..8f1fd143 100644 --- a/password_reset/views.py +++ b/password_reset/views.py @@ -1,15 +1,18 @@ import datetime - +from django.core.mail import EmailMessage from django.conf import settings from django.contrib.sites.models import Site, RequestSite from django.core import signing from django.core.mail import send_mail +from django.template import Context from django.core.urlresolvers import reverse, reverse_lazy from django.shortcuts import get_object_or_404, redirect from django.http import Http404 from django.template import loader from django.utils import timezone from django.views import generic +from django.template.loader import get_template +from email.MIMEImage import MIMEImage from .forms import PasswordRecoveryForm, PasswordResetForm from .utils import get_user_model, get_username @@ -52,7 +55,7 @@ class Recover(SaltMixin, generic.FormView): form_class = PasswordRecoveryForm template_name = 'password_reset/recovery_form.html' success_url_name = 'password_reset_sent' - email_template_name = 'password_reset/recovery_email.txt' + email_template_name = 'password_reset/recovery_email_expo.html' email_subject_template_name = 'password_reset/recovery_email_subject.txt' search_fields = ['username', 'email'] @@ -85,12 +88,35 @@ class Recover(SaltMixin, generic.FormView): 'token': signing.dumps(self.user.pk, salt=self.salt), 'secure': self.request.is_secure(), } - body = loader.render_to_string(self.email_template_name, - context).strip() + + #body = loader.render_to_string(self.email_template_name, + # context).strip() + message = get_template(self.email_template_name).render(Context(context)) subject = loader.render_to_string(self.email_subject_template_name, context).strip() - send_mail(subject, body, settings.DEFAULT_FROM_EMAIL, - [self.user.email]) + + msg = EmailMessage(subject, message, settings.DEFAULT_FROM_EMAIL, [self.user.email]) + msg.content_subtype = "html" + + images =(('/img/logo_reg.png', 'logo'), + ('/img/soc-medias/sm-icon-rss.png', 'rss'), + ('/img/soc-medias/sm-icon-fb.png', 'fb'), + ('/img/soc-medias/sm-icon-lin.png', 'linkedin'), + ('/img/soc-medias/sm-icon-vk.png', 'vk'), + ('/img/soc-medias/sm-icon-twit.png', 'twit'), + ('/img/mail-logo-2.jpg','logo2')) + for img in images: + fp = open(settings.STATIC_ROOT+img[0], 'rb') + msg_img = MIMEImage(fp.read()) + fp.close() + msg_img.add_header('Content-ID', '<'+img[1]+'>') + msg.attach(msg_img) + + + msg.send() + + #send_mail(subject, body, settings.DEFAULT_FROM_EMAIL, + # [self.user.email]) def form_valid(self, form): self.user = form.cleaned_data['user'] diff --git a/place_exposition/admin.py b/place_exposition/admin.py index ce467f5a..52e97bec 100644 --- a/place_exposition/admin.py +++ b/place_exposition/admin.py @@ -20,7 +20,7 @@ import random #custom fields from functions.custom_views import objects_list, delete_object from functions.views_help import get_referer -from functions.admin_views import AdminView, AdminListView, upload_photo +from functions.admin_views import AdminView, AdminListView, upload_photo, FormView def exposition_all(request): @@ -282,3 +282,28 @@ class PlaceExpositionListView(AdminListView): def upload_place_photo(request, place_id): return upload_photo(request, place_id, PlaceExposition) + + + + +def edit_hall(request, place_url, hall_id): + place = get_object_or_404(PlaceExposition, url=place_url) + hall = get_object_or_404(Hall, id=hall_id) + + if request.POST: + form = HallForm(request.POST) + if form.is_valid(): + form.save(place, hall_id) + return HttpResponseRedirect('/admin/place_exposition/%s/'%place.url) + else: + + data = {'capacity': hall.capacity, 'number': hall.number} + for code, name in settings.LANGUAGES: + trans_obj = Hall._meta.translations_model.objects.get(language_code = code, master__id=hall.id) #access to translated fields + data['name_%s'%code] = trans_obj.name + form = HallForm(initial=data) + context = {'form': form, 'languages': settings.LANGUAGES} + context.update(csrf(request)) + + return render_to_response('admin/place_exposition/hall.html', context) + diff --git a/place_exposition/admin_urls.py b/place_exposition/admin_urls.py index 47ab735d..d1283dc1 100644 --- a/place_exposition/admin_urls.py +++ b/place_exposition/admin_urls.py @@ -7,10 +7,11 @@ urlpatterns = patterns('place_exposition.admin', url(r'^add-hall/(?P.*)/$', 'add_hall'), url(r'^delete-hall/(?P.*)/$', 'delete_hall'), url(r'^upload-photo/(?P.*)/$', 'upload_place_photo'), + url(r'^hall/(?P.*)/(?P.*)/$', 'edit_hall'), url(r'^all/$', PlaceExpositionListView.as_view()), #url(r'^add.*/$', 'exposition_add'), - #url(r'^delete/(?P.*)/$', 'exposition_delete'), + url(r'^delete/(?P.*)/$', 'exposition_delete'), #url(r'^change/(?P.*)/$', 'exposition_change'), #url(r'^copy/(?P.*)/$', 'place_exposition_copy'), url(r'^(?P.*)/$', PlaceExpositionView.as_view()), diff --git a/place_exposition/forms.py b/place_exposition/forms.py index d8a4a818..7ce33ccd 100644 --- a/place_exposition/forms.py +++ b/place_exposition/forms.py @@ -27,13 +27,13 @@ class ExpositionForm(forms.Form): """ types = [(item1, item2) for item1, item2 in EXPOSITION_TYPE] type = forms.ChoiceField(required=False, choices=types) - logo = forms.ImageField(label='Logo', required=False) + logo = forms.ImageField(label='Logo', required=False, max_length=500) country = forms.ChoiceField(label='Страна', choices=[(c.id, c.name) for c in Country.objects.all()]) # creates select input with empty choices cause it will be filled with ajax city = forms.CharField(label='Город', widget=forms.HiddenInput()) - address = forms.CharField(label='Адресс', widget=LocationWidget, required=False) + address = forms.CharField(label='Адрес', widget=LocationWidget, required=False) phone = forms.CharField(label='Телефон', required=False, widget=forms.TextInput(attrs={'placeholder': 'Введите телефон'})) @@ -48,7 +48,7 @@ class ExpositionForm(forms.Form): widget=forms.TextInput(attrs={'placeholder': 'Год основания'})) total_area = forms.CharField(label='Общая выставочная площадь', required=False, widget=forms.TextInput(attrs={'placeholder': 'Общая выст. площадь'})) - closed_area = forms.CharField(label='Закрытая выствочная площадь', required=False, + closed_area = forms.CharField(label='Закрытая выставочная площадь', required=False, widget=forms.TextInput(attrs={'placeholder': 'Закр. выст. площадь'})) open_area = forms.CharField(label='Открытая выставочная площадь', required=False, widget=forms.TextInput(attrs={'placeholder': 'Откр. выст. площадь'})) @@ -62,10 +62,10 @@ class ExpositionForm(forms.Form): children_room = forms.BooleanField(label='Детская комната', required=False) disabled_service = forms.BooleanField(label='Сервис для инвалидов', required=False) conference_centre = forms.BooleanField(label='Конгресс-центр', required=False) - business_centre = forms.BooleanField(label='Бизнес центр', required=False) + business_centre = forms.BooleanField(label='Бизнес-центр', required=False) online_registration = forms.BooleanField(label='Онлайн регистрация', required=False) cafe = forms.BooleanField(label='Кафе', required=False) - terminals = forms.BooleanField(label='Информационые терминалы', required=False) + terminals = forms.BooleanField(label='Информационные терминалы', required=False) parking = forms.BooleanField(label='Парковка', required=False) press_centre = forms.BooleanField(label='Пресс-центр', required=False) mobile_application = forms.BooleanField(label='Мобильное приложение', required=False) @@ -278,8 +278,10 @@ class HallForm(forms.ModelForm): class HallForm(forms.Form): url = '/admin/place_exposition/add-hall/' - number = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:30px'}),required=False) - capacity = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:60px'}), required=False) + number = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:30px'}),required=False, + label='Номер') + capacity = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:60px'}), required=False, + label='Вместимость') def __init__(self, *args, **kwargs): """ create dynamical translated fields fields @@ -294,11 +296,6 @@ class HallForm(forms.Form): required = True if lid == 0 else False self.fields['name_%s' % code] = forms.CharField(label='Название', required=required) - def clean_number(self): - cleaned_data = super(HallForm, self).clean() - number = cleaned_data.get('number').strip() - return is_positive_integer(number, 'Номер должен состоять из цифр') - def clean_capacity(self): cleaned_data = super(HallForm, self).clean() capacity = cleaned_data.get('capacity').strip() @@ -314,6 +311,7 @@ class HallForm(forms.Form): hall.number = data['number'] hall.place_exposition = place_exposition fill_with_signal(Hall, hall, data) + hall.save() return hall diff --git a/place_exposition/management/commands/convert_logo.py b/place_exposition/management/commands/convert_logo.py index 14f5e3e7..c37be278 100644 --- a/place_exposition/management/commands/convert_logo.py +++ b/place_exposition/management/commands/convert_logo.py @@ -27,15 +27,9 @@ def handle_place(place): place.save() - class Command(BaseCommand): def handle(self, *args, **options): - for place in PlaceExposition.objects.all('en'): - - if place.files.filter(purpose='logo').exists(): handle_place(place) - print(place) - - + print(place) \ No newline at end of file diff --git a/place_exposition/management/commands/place_exposition_load.py b/place_exposition/management/commands/place_exposition_load.py index b47945e8..c1b5435a 100644 --- a/place_exposition/management/commands/place_exposition_load.py +++ b/place_exposition/management/commands/place_exposition_load.py @@ -1,99 +1,114 @@ # -*- coding: utf-8 -*- from django.core.management.base import BaseCommand, CommandError +import xlrd from place_exposition.models import PlaceExposition -import xlrd, xlwt from import_xls.excel_settings import import_settings, place_exp_sett from django.conf import settings -from import_xls.import_forms import google_address + +PLACE_FILE = settings.MEDIA_ROOT+'import/places_ru.xls' class Command(BaseCommand): def handle(self, *args, **options): - f = open(settings.MEDIA_ROOT+'/import/places_ru.xlsx', 'r') + f = open(PLACE_FILE, 'r') 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)] labels = [label for label in row_list[0]] - for row_number, row in enumerate(row_list): + existing = 0 + + for row_number, row in enumerate(row_list[1:]): + new = 0 # go through all rows in file - if row_number > 0: - # first field is label - if row[0] != '': - # in first column ids + if row[0] != '': + # in first column ids - try: - object = PlaceExposition.objects.language('ru').get(id=int(row[0])) - except ValueError: - object = PlaceExposition() - object.translate('ru') - - except PlaceExposition.DoesNotExist: - object = PlaceExposition(id= int(row[0])) - object.translate('ru') - else: - # if id blank - its a new place - object = PlaceExposition + try: + object = PlaceExposition.objects.language('ru').get(id=int(row[0])) + existing += 1 + except ValueError: + object = PlaceExposition() object.translate('ru') - 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 + new = 1 - if setting.get('method'): - if cell != "": - methods.append({'func': setting['func'], 'value': cell, 'purpose': setting.get('purpose')}) - continue + except PlaceExposition.DoesNotExist: + object = PlaceExposition(id= int(row[0])) + object.translate('ru') + existing += 1 + new = 1 + else: + # if id blank - its a new place + object = PlaceExposition + object.translate('ru') - field_name = setting['field'] - - - 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 - - # in function we add language(need for relation fields) - # and extra value from object (like for city need country) - value = func(cell, 'ru', getattr(object, extra_value)) - else: - value = func(cell) - #if field_name =='adress': - # setattr(object, 'address', google_address(value)) - setattr(object, field_name, value) - - object.save() - print('post save %s'% str(object)) - """ - try: - print(object) - #object.save() - except IntegrityError: + 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 - #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 + + 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 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 + + # in function we add language(need for relation fields) + # and extra value from object (like for city need country) + value = func(cell, 'ru', getattr(object, extra_value)) + + + else: + value = func(cell) + #if field_name =='adress': + # setattr(object, 'address', google_address(value)) + if field_name == 'city' and new == 0: + pass else: try: - func(object, method['value']) - except: - continue + setattr(object, field_name, value) + except ValueError, e: + print(value, field_name) + + object.save() + print('post save %s'% str(object)) + """ + try: + print(object) + #object.save() + + 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 \ No newline at end of file diff --git a/place_exposition/models.py b/place_exposition/models.py index 5d90d64b..0c572908 100644 --- a/place_exposition/models.py +++ b/place_exposition/models.py @@ -78,8 +78,9 @@ class PlaceExposition(TranslatableModel, ExpoMixin): press_centre = models.NullBooleanField() mobile_application = models.NullBooleanField() # - logo = models.ImageField(verbose_name='Logo', upload_to=logo_name, blank=True) + logo = models.ImageField(verbose_name='Logo', upload_to=logo_name, blank=True, max_length=255) rating = models.IntegerField(default=0) + partner = models.NullBooleanField(default=0) # delete after profiling files = generic.GenericRelation('file.FileModel', content_type_field='content_type', object_id_field='object_id') @@ -255,7 +256,7 @@ class Hall(TranslatableModel): Create Hall model which saves information about halls in PlaceExposition """ place_exposition = models.ForeignKey(PlaceExposition, related_name='halls') - number = models.PositiveIntegerField(blank=True, null=True) + number = models.CharField(blank=True, max_length=6) capacity = models.PositiveIntegerField(blank=True, null=True) translations = TranslatedFields( name = models.CharField(max_length=255, blank=True) @@ -263,7 +264,42 @@ class Hall(TranslatableModel): +def calculate_rating(place): + rating_simple = {'address': 20, 'phone': 5, 'fax': 5, 'email': 5, + 'web_page': 5, 'logo': 20, 'event_in_year': 5, 'total_area': 5, 'closed_area': 5, + 'total_pavilions': 5, 'description':15, 'foundation_year': 5, 'total_halls': 5, 'virtual_tour': 5 } + rating_methods = {'theme': 10, 'tag': 5, 'photo':5} + # base rating + rating = 100 + for key, value in rating_simple.iteritems(): + if getattr(place, key): + rating += value + + place.rating = rating + # call to prevent recursion + post_save.disconnect(create_place, sender=PlaceExposition) + place.save() + post_save.connect(create_place, sender=PlaceExposition) + + +def create_place(sender, instance, created, **kwargs): + post_save_handler(sender, instance=instance, **kwargs) + calculate_rating(instance) #test pre_save.connect(pre_save_handler, sender=PlaceExposition) -post_save.connect(post_save_handler, sender=PlaceExposition) -post_save.connect(post_save_handler, sender=Hall) \ No newline at end of file +post_save.connect(create_place, sender=PlaceExposition) +post_save.connect(post_save_handler, sender=Hall) + + + + +""" +def calculate_rating_for_translations(sender, instance, created, **kwargs): + company = instance.master + post_save.disconnect(calculate_rating_for_translations, sender=Company._meta.translations_model) + calculate_rating(company) + post_save.connect(calculate_rating_for_translations, sender=Company._meta.translations_model) + +post_save.connect(create_company, sender=Company) +post_save.connect(calculate_rating_for_translations, sender=Company._meta.translations_model) +""" \ No newline at end of file diff --git a/place_exposition/urls.py b/place_exposition/urls.py index af64dd62..6f68b806 100644 --- a/place_exposition/urls.py +++ b/place_exposition/urls.py @@ -9,18 +9,17 @@ urlpatterns = patterns('', url(r'search/', PlaceSearchView.as_view()), # correct #url(r'country/$', PlaceCountryCatalog.as_view()), - url(r'country/(?P.*)/page/(?P\d+)/$', PlaceCountryCatalog.as_view()), - url(r'country/(?P.*)/$', PlaceCountryCatalog.as_view()), + url(r'country/(?P.*)/page/(?P\d+)/$', PlaceCountryCatalog.as_view(), {'meta_id':49}), + url(r'country/(?P.*)/$', PlaceCountryCatalog.as_view(), {'meta_id':49}), # correct #url(r'expo/city/$', ExpositionByCity.as_view()), - url(r'city/(?P.*)/page/(?P\d+)/$', PlaceCityCatalog.as_view()), - url(r'city/(?P.*)/$', PlaceCityCatalog.as_view()), - + url(r'city/(?P.*)/page/(?P\d+)/$', PlaceCityCatalog.as_view(), {'meta_id':48}), + url(r'city/(?P.*)/$', PlaceCityCatalog.as_view(), {'meta_id':48}), #!!! url(r'(?P.*)/photo/page/(?P\d+)/$', PlacePhoto.as_view()), url(r'(?P.*)/photo/$', PlacePhoto.as_view()), #url(r'expo/(?P.*)/service/(?P.*)/$', ExpositionServiceView.as_view()), - url(r'(?P.*)/$', PlaceDetail.as_view()), - url(r'page/(?P\d+)/$', PlaceList.as_view()), - url(r'$', PlaceList.as_view()), + url(r'page/(?P\d+)/$', PlaceList.as_view(), {'meta_id':46}), + url(r'(?P.*)/$', PlaceDetail.as_view(), {'meta_id':47}), + url(r'$', PlaceList.as_view(), {'meta_id':46}), ) diff --git a/place_exposition/views.py b/place_exposition/views.py index aac4d1dc..c72b2c38 100644 --- a/place_exposition/views.py +++ b/place_exposition/views.py @@ -13,6 +13,10 @@ from place_conference.models import PlaceConference from country.models import Country from city.models import City from models import PlaceExposition +from meta.views import MetadataMixin +from django.conf import settings +from functions.cache_mixin import JitterCacheMixin, CacheMixin + def catalog(request): expo = list(PlaceExposition.objects.all()) @@ -47,7 +51,8 @@ class PlaceSearchView(ExpoSearchView): search_form = PlaceSearchForm model = PlaceExposition -class PlaceDetail(DetailView): +class PlaceDetail(JitterCacheMixin, MetadataMixin, DetailView): + cache_range = settings.CACHE_RANGE model = PlaceExposition search_form = PlaceSearchForm slug_field = 'url' @@ -97,7 +102,6 @@ class PlaceDetail(DetailView): class PlacePhoto(ListView): template_name = 'client/place/photo.html' obj = None - search_form = PlaceSearchForm def get_queryset(self): slug = self.kwargs.get('slug') @@ -115,11 +119,10 @@ class PlacePhoto(ListView): def get_context_data(self, **kwargs): context = super(PlacePhoto, self).get_context_data(**kwargs) context['object'] = self.obj - context['search_form'] = self.search_form return context -class PlaceList(ListView): +class PlaceList(JitterCacheMixin, MetadataMixin, ListView): model = PlaceExposition paginate_by = 10 template_name = 'client/place/place_list.html' @@ -127,8 +130,8 @@ class PlaceList(ListView): def get_queryset(self): - lang = translation.get_language() - qs = super(PlaceList, self).get_queryset().filter(language_code=lang) + #qs = super(PlaceList, self).get_queryset().order_by('-rating') + qs= PlaceExposition.objects.language().select_related('country', 'city').all().order_by('-rating') conf_qs = PlaceConference.objects.language().all() return list(qs)+list(conf_qs) @@ -138,17 +141,16 @@ class PlaceList(ListView): return context -class PlaceCatalog(ListView): +class PlaceCatalog(JitterCacheMixin, MetadataMixin, ListView): + cache_range = settings.CACHE_RANGE model = PlaceExposition paginate_by = 10 - template_name = 'place/catalog.html' - search_form = PlaceSearchForm + template_name = 'client/place/catalog.html' filter_object = None def get_context_data(self, **kwargs): context = super(PlaceCatalog, self).get_context_data(**kwargs) - context['search_form'] = self.search_form context['filter_object'] = self.filter_object context['catalog_url'] = self.catalog_url @@ -161,9 +163,10 @@ class PlaceCountryCatalog(PlaceCatalog): def get_queryset(self): slug = self.kwargs.get('slug') country = get_object_or_404(Country, url=slug) + self.kwargs['country'] = country self.filter_object = country - qs = self.model.objects.language().filter(country=country).order_by('-rating') - conf_qs = PlaceConference.objects.language().filter(country=country) + qs = self.model.objects.language().select_related('country', 'city').filter(country=country).order_by('-rating') + conf_qs = PlaceConference.objects.language().select_related('country', 'city').filter(country=country) return list(qs) + list(conf_qs) @@ -174,7 +177,8 @@ class PlaceCityCatalog(PlaceCatalog): def get_queryset(self): slug = self.kwargs.get('slug') city = get_object_or_404(City, url=slug) + self.kwargs['city'] = city self.filter_object = city - qs = self.model.objects.language().filter(city=city).order_by('-rating') - conf_qs = PlaceConference.objects.language().filter(city=city) + qs = self.model.objects.language().select_related('country', 'city').filter(city=city).order_by('-rating') + conf_qs = PlaceConference.objects.language().select_related('country', 'city').filter(city=city) return list(qs) + list(conf_qs) \ No newline at end of file diff --git a/proj/admin.py b/proj/admin.py index 1d2114b2..3258345e 100644 --- a/proj/admin.py +++ b/proj/admin.py @@ -9,9 +9,11 @@ from file.models import TmpFile, FileModel from file.forms import FileModelForm, FileForm from city.models import City from theme.models import Tag +from article.models import Article from django.db.models.loading import get_model + def admin_home(request): return render_to_response('base.html') @@ -39,6 +41,24 @@ def ajax_tag(request): else: #request empty - send empty array return HttpResponse('[]', content_type='application/json') + + +def get_news(request): + """ + + return array of tags (id, name) filtered by theme values from request + + """ + term = request.GET['term'].capitalize() + if not term: + qs = Article.objects.news()[:50] + else: + qs = Article.objects.news().filter(translations__main_title__contains=term) + result = [{'id': item.id, 'label': item.main_title} for item in qs] + + return HttpResponse(json.dumps(result), content_type='application/json') + + ''' def ajax_post_file(request, obj_id=None): """ @@ -159,6 +179,38 @@ def ajax_post_timetable(request, obj_id=None): else: return HttpResponse('error') +from exposition.models import Statistic +from exposition.forms import StatisticForm +def ajax_post_stat(request, obj_id=None): + response = {'success': False} + if request.GET: + form = StatisticForm(request.GET) + if form.is_valid(): + + exp = Exposition.objects.safe_get(id=obj_id) + if exp: + form.save(exp) + response['success'] = True + else: + response.update({'errors': form.errors}) + + return HttpResponse(json.dumps(response), content_type='application/json') + +def ajax_delete_stat(request, id): + redirect_to = request.META.get('HTTP_REFERER') + + + if id: + try: + Statistic.objects.get(id=id).delete() + except Statistic.DoesNotExist: + pass + + + return HttpResponseRedirect(redirect_to) + + + def ajax_delete_timetable(request): if request.GET: diff --git a/proj/admin_urls.py b/proj/admin_urls.py index f499cc8c..2ceee92f 100644 --- a/proj/admin_urls.py +++ b/proj/admin_urls.py @@ -29,6 +29,7 @@ urlpatterns = required( url(r'^translator/', include('translator.admin_urls')), url(r'^webinar/', include('webinar.admin_urls')), url(r'^settings/', include('settings.admin_urls')), + url(r'^meta/', include('meta.admin_urls')), url(r'^language/add/', 'directories.admin.language_add'), url(r'^currency/add/', 'directories.admin.currency_add'), # ajax requests @@ -36,6 +37,8 @@ urlpatterns = required( url(r'^ajax_post_file/', 'proj.admin.ajax_post_file'), url(r'^ajax_post_photo/(?P\d+)/$', 'proj.admin.ajax_post_photo'),#must be before /ajax_post_photo/ url(r'^ajax_post_photo/', 'proj.admin.ajax_post_photo'), + url(r'^ajax_post_stat/(?P\d+)/$', 'proj.admin.ajax_post_stat'), + url(r'^ajax_delete_stat/(?P\d+)/', 'proj.admin.ajax_delete_stat'), url(r'^ajax_post_timetable/(?P\d+)/$', 'proj.admin.ajax_post_timetable'),#must be before /ajax_post_timetable/ url(r'^ajax_post_timetable/', 'proj.admin.ajax_post_timetable'), url(r'^ajax_delete_timetable/', 'proj.admin.ajax_delete_timetable'), @@ -43,6 +46,7 @@ urlpatterns = required( url(r'^ajax_delete_file/', 'proj.admin.ajax_delete_file'), url(r'^ajax_city/', 'proj.admin.ajax_city'), url(r'^ajax_tag/', 'proj.admin.ajax_tag'), + url(r'^ajax/get-news/', 'proj.admin.get_news'), # url(r'^ckeditor/', include('ckeditor.urls')), url(r'^tinymce/', include('tinymce.urls')), diff --git a/proj/production.py b/proj/production.py index 4360eb31..9ff19ae6 100644 --- a/proj/production.py +++ b/proj/production.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- # Django local settings -DEBUG = True # изменить когда будет продакшн +DEBUG = False + +ALLOWED_HOSTS = ['hit.expomap.ru', '195.66.79.152', '195.66.79.145', 'expomap.ru'] DATABASES = { 'default': { diff --git a/proj/settings.py b/proj/settings.py index 772be17e..8656fdeb 100644 --- a/proj/settings.py +++ b/proj/settings.py @@ -22,23 +22,27 @@ DATABASES = { 'NAME': 'test2', 'USER': 'kotzilla', 'PASSWORD': 'qazedc', - 'HOST': '', + 'HOST': '195.66.79.152', 'PORT': '', } } -''' + + CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', - 'LOCATION': '127.0.0.1:11211', + "default": { + "BACKEND": "redis_cache.cache.RedisCache", + "LOCATION": "127.0.0.1:6379:1", + "OPTIONS": { + "CLIENT_CLASS": "redis_cache.client.DefaultClient", + }, } } -''' + # Hosts/domain names that are valid for this site; required if DEBUG is False # See https://docs.djangoproject.com/en/1.5/ref/settings/#allowed-hosts -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ['hit.expomap.ru', '195.66.79.152', '195.66.79.145', 'expomap.ru'] # Local time zone for this installation. Choices can be found here: # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name @@ -71,15 +75,14 @@ USE_I18N = True # If you set this to False, Django will not format dates, numbers and # calendars according to the current locale. -USE_L10N = True +USE_L10N = False # If you set this to False, Django will not use timezone-aware datetimes. -USE_TZ = True +USE_TZ = False -# Absolute filesystem path to the directory that will hold user-uploaded files. -# Example: "/var/www/example.com/media/" -MEDIA_ROOT = os.path.join(SITE_ROOT, 'media/')#'/home/kotzilla/Documents/qwer/proj/media/' -CKEDITOR_UPLOAD_PATH = os.path.join(SITE_ROOT, 'media/upload')#'/home/kotzilla/Documents/qwer/proj/media/upload' + +MEDIA_ROOT = os.path.join(SITE_ROOT, 'media/') +CKEDITOR_UPLOAD_PATH = os.path.join(SITE_ROOT, 'media/upload') CKEDITOR_CONFIGS = { @@ -95,37 +98,13 @@ CKEDITOR_CONFIGS = { }, } -#TINYMCE_JS_URL = os.path.join(MEDIA_ROOT, "js/tiny_mce/tiny_mce.js") -#TINYMCE_DEFAULT_CONFIG = { -# 'plugins': "table,spellchecker,paste,searchreplace", -# 'theme': "advanced", -# 'cleanup_on_startup': True, -# 'custom_undo_redo_levels': 10, -# 'width' : 565, -# 'height' : 100 -#} -#TINYMCE_SPELLCHECKER = True -#TINYMCE_COMPRESSOR = True - -# URL that handles the media served from MEDIA_ROOT. Make sure to use a -# trailing slash. -# Examples: "http://example.com/media/", "http://media.example.com/" + MEDIA_URL = '/media/' -# Absolute path to the directory static files should be collected to. -# Don't put anything in this directory yourself; store your static files -# in apps' "static/" subdirectories and in STATICFILES_DIRS. -# Example: "/var/www/example.com/static/" STATIC_ROOT = os.path.join(SITE_ROOT, 'static') -# URL prefix for static files. -# Example: "http://example.com/static/", "http://static.example.com/" STATIC_URL = '/static/' -# Additional locations of static files - -# List of finder classes that know how to find static files in -# various locations. STATICFILES_FINDERS = ( 'django.contrib.staticfiles.finders.FileSystemFinder', 'django.contrib.staticfiles.finders.AppDirectoriesFinder', @@ -135,7 +114,7 @@ STATICFILES_FINDERS = ( # Make this unique, and don't share it with anybody. SECRET_KEY = '=yz1@ko%1s8bmel)c84#s*xpxn%4(1e+smdnh*@rdm*5%v!mln' -# List of callables that know how to import templates from various sources. + TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', @@ -160,8 +139,6 @@ TEMPLATE_CONTEXT_PROCESSORS = ( MIDDLEWARE_CLASSES = ( # 'django.middleware.cache.UpdateCacheMiddleware', - - 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware', @@ -173,7 +150,6 @@ MIDDLEWARE_CLASSES = ( # Uncomment the next line for simple clickjacking protection: 'django.middleware.clickjacking.XFrameOptionsMiddleware', - #'debug_toolbar.middleware.DebugToolbarMiddleware', ) @@ -187,7 +163,7 @@ TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". # Always use forward slashes, even on Windows. # Don't forget to use absolute paths, not relative paths. - os.path.join(SITE_ROOT, 'templates'), + # os.path.join(SITE_ROOT, 'templates/debug_toolbar'), os.path.join(SITE_ROOT, 'templates/admin'), os.path.join(SITE_ROOT, 'templates/admin/accounts'), os.path.join(SITE_ROOT, 'templates/admin/article'), @@ -215,6 +191,7 @@ TEMPLATE_DIRS = ( os.path.join(SITE_ROOT, 'templates/client/exposition'), os.path.join(SITE_ROOT, 'templates/client/photoreport'), os.path.join(SITE_ROOT, 'templates/client/includes'), + os.path.join(SITE_ROOT, 'templates'), #os.path.join(SITE_ROOT, 'templates/client/popups'), ) @@ -223,16 +200,13 @@ LOGIN_URL='/' #registration info ACCOUNT_ACTIVATION_DAYS=2 # mail settings -EMAIL_USE_TLS = True -EMAIL_HOST = 'smtp.gmail.com' -#EMAIL_HOST = 'localhost' -#EMAIL_HOST_USER = 'kotzilla' -EMAIL_HOST_USER = 'kotzillla@gmail.com' -EMAIL_HOST_PASSWORD = 'fitteR2006!' - - -EMAIL_PORT = 587 -#DEFAULT_FROM_EMAIL = 'kotzillla@gmail.com' +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_HOST = 'localhost' +EMAIL_HOST_USER = '' +EMAIL_HOST_PASSWORD = '' +EMAIL_USE_TLS = False +EMAIL_PORT = 25 +DEFAULT_FROM_EMAIL = "expomap.ru" AUTHENTICATION_BACKENDS = ( @@ -303,6 +277,7 @@ INSTALLED_APPS = ( 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.humanize', + 'django.contrib.sitemaps', 'haystack', #custom modules 'accounts', @@ -330,32 +305,27 @@ INSTALLED_APPS = ( 'translator', 'webinar', 'meta', + 'banners', #django modules - 'sorl.thumbnail', - 'photologue', - 'sortedm2m', - 'hvad', - 'tinymce', - 'ckeditor', - 'django_messages', + 'sorl.thumbnail', # for logos + 'photologue', # photogallery + 'sortedm2m', # photologue dependence + 'hvad', # + 'tinymce', # ??? + 'ckeditor', # wysiwig editor in admin + 'django_messages', # messages 'bitfield', - 'djutils', - 'pytils', - 'pymorphy', - 'password_reset', - #'social_auth', - 'social.apps.django_app.default', - # 'south', - #'debug_toolbar', + 'djutils', # ?? + 'pytils', # ?? + 'pymorphy', # ?? + 'password_reset', # reset password + 'django_crontab', # crons + 'social.apps.django_app.default', # social auth ) -INTERNAL_IPS = ('176.121.5.82',) -DEBUG_TOOLBAR_PATCH_SETTINGS = False -#DEBUG_TOOLBAR_PANELS = ( - # 'debug_toolbar.panels.profiling.ProfilingPanel', -#) + PYMORPHY_DICTS = { - 'ru': { 'dir': '/home/www/proj/settings/russian_dicts' }, + 'ru': { 'dir': os.path.join(SITE_ROOT, 'settings/russian_dicts')} #'/home/www/proj/settings/russian_dicts' }, } # search backend @@ -398,18 +368,82 @@ LOGGING = { } } -THUMBNAIL_DEBUG = True + +CRONJOBS = [ + ('0 */1 * * *', 'django.core.management.call_command', ['update_index conference --age=1']), + ('0 */1 * * *', 'django.core.management.call_command', ['update_index exposition --age=1']), + ('0 */12 * * *', 'django.core.management.call_command', ['update_index place_exposition --age=12']), + ('0 */24 * * *', 'django.core.management.call_command', ['update_index company --age=24']), + ('0 */24 * * *', 'django.core.management.call_command', ['update_index theme --age=24']), + ('0 */24 * * *', 'django.core.management.call_command', ['update_index tag --age=24']), +] + +THUMBNAIL_DEBUG = DEBUG CALLBACK_EMAIL = 'kotzilla@ukr.net' BOOKING_AID = '333667' -""" + +ADMIN_PAGINATION = 20 +CLIENT_PAGINATION = 15 +TEMPLATE_DEBUG = DEBUG +NO_LOGO = '/static/client/img/no-logo.png' + +# events settings +CURRENCY = ('RUB', 'USD', 'EUR', 'RMB', 'GBP', 'AED', 'SGD', 'TRY', 'CZK', 'CHF', 'SEK', 'LKR', 'UAH', 'IDR', 'PLN','JPY') +BIT_AUDIENCE = (('experts', _(u'Специалисты')), ('experts and consumers', _(u'Специалисты и потребители')), + ('general public', _(u'Широкая публика'))) + +MONTHES = {'jan': {'value': 1, 'name': _(u'Январь')}, 'feb': {'value': 2, 'name': _(u'Февраль')}, + 'mar': {'value': 3, 'name': _(u'Март')}, 'apr': {'value': 4, 'name': _(u'Апрель')}, + 'may': {'value': 5, 'name': _(u'Май')}, 'jun': {'value': 6, 'name': _(u'Июнь')}, + 'jul': {'value': 7, 'name': _(u'Июль')}, 'aug': {'value': 8, 'name': _(u'Август')}, + 'sep': {'value': 9, 'name': _(u'Сентябрь')}, 'oct': {'value': 10, 'name': _(u'Октябрь')}, + 'nov': {'value': 11, 'name': _(u'Ноябрь')}, 'dec': {'value': 12, 'name': _(u'Декабрь')}} + +SNG_COUNTRIES = [159, 186, 31, 6, 99, 13, 189, 64] + +# cache pages in random seconds. random in this range +CACHE_RANGE = [60, 120] + try: from local import * except ImportError, e: - from production import * + pass + + +# debug_toolbar settings """ -ADMIN_PAGINATION = 20 -CLIENT_PAGINATION = 15 -TEMPLATE_DEBUG = DEBUG +if DEBUG: + DEBUG_TOOLBAR_PATCH_SETTINGS = False + INTERNAL_IPS = ('127.0.0.1','176.121.5.82', '176.121.11.162', '77.123.47.46') + + MIDDLEWARE_CLASSES += ( + 'debug_toolbar.middleware.DebugToolbarMiddleware', + ) + + INSTALLED_APPS += ( + 'debug_toolbar', + ) + JQUERY_URL = os.path.join(SITE_ROOT, 'static/client/js/jquery-ui-1.10.4.custom.min.js'), + DEBUG_TOOLBAR_PANELS = [ + #'debug_toolbar.panels.versions.VersionsPanel', + #'debug_toolbar.panels.timer.TimerPanel', + #'debug_toolbar.panels.settings.SettingsPanel', + #'debug_toolbar.panels.headers.HeadersPanel', + #'debug_toolbar.panels.request.RequestPanel', + 'debug_toolbar.panels.sql.SQLPanel', + #'debug_toolbar.panels.staticfiles.StaticFilesPanel', + #'debug_toolbar.panels.templates.TemplatesPanel', + #'debug_toolbar.panels.cache.CachePanel', + #'debug_toolbar.panels.signals.SignalsPanel', + #'debug_toolbar.panels.logging.LoggingPanel', + #'debug_toolbar.panels.redirects.RedirectsPanel', +] + + #DEBUG_TOOLBAR_CONFIG = { + # 'INTERCEPT_REDIRECTS': False, + #} + +""" \ No newline at end of file diff --git a/proj/sitemaps.py b/proj/sitemaps.py new file mode 100644 index 00000000..265f4243 --- /dev/null +++ b/proj/sitemaps.py @@ -0,0 +1,141 @@ +import datetime +from django.contrib.sitemaps import Sitemap +from exposition.models import Exposition +from conference.models import Conference +from city.models import City +from country.models import Country +from theme.models import Theme, Tag +from article.models import Article +from django.core.urlresolvers import reverse +from django.core.paginator import Paginator + + +class Abstract(Sitemap): + changefreq = 'weekly' + priority = 0.8 + + def lastmod(self, obj): + return datetime.date.today() + + +class ExpoCard(Abstract): + changefreq = 'weekly' + priority = 0.8 + + def items(self): + return Exposition.enable.upcoming() + + def lastmod(self, obj): + return obj.modified + +class ExpoCity(Abstract): + + def items(self): + return City.used.expo_cities() + + def location(self, obj): + return "/expo/city/%s/" % obj.url + +class ExpoCountry(Abstract): + def items(self): + return Country.objects.expo_countries() + + def location(self, obj): + return "/expo/country/%s/" % obj.url + +class ExpoTheme(Abstract): + def items(self): + return Theme.active.expo_themes() + + def location(self, obj): + return "/expo/theme/%s/" % obj.url + +class ExpoTag(Abstract): + def items(self): + return Tag.active.expo_tag() + + def location(self, obj): + return "/expo/tag/%s/" % obj.url + + + +class ConfCard(Sitemap): + changefreq = 'weekly' + priority = 0.8 + + def items(self): + return Conference.enable.upcoming() + + def lastmod(self, obj): + return obj.modified + + def location(self, obj): + return "/conference/%s/" % obj.url + + +class ConfCity(Abstract): + + def items(self): + return City.used.conference_cities() + + def location(self, obj): + return "/conference/city/%s/" % obj.url + +class ConfCountry(Abstract): + def items(self): + return Country.objects.conference_countries() + + def location(self, obj): + return "/conference/country/%s/" % obj.url + +class ConfTheme(Abstract): + def items(self): + return Theme.active.conference_themes_with_count() + + def location(self, obj): + return "/conference/theme/%s/" % obj.url + +class ConfTag(Abstract): + def items(self): + return Tag.active.conference_tags() + + def location(self, obj): + return "/conference/tag/%s/" % obj.url + + +class NewsSiteMap(Abstract): + priority = 0.5 + def items(self): + return Article.objects.news().filter(publish_date__isnull=False) + + def location(self, obj): + return "/news/%s/" % obj.slug + +class BlogsSiteMap(Abstract): + priority = 0.5 + def items(self): + return Article.objects.blogs().filter(publish_date__isnull=False) + + def location(self, obj): + return "/blogs/%s/" % obj.slug + + +class SimpleAbstract(Sitemap): + priority = 0.5 + + def location(self, item): + return item + + +class Important(SimpleAbstract): + priority = 1 + + def items(self): + return ['', '/expo/', '/conference/', '/conference/country/', '/conference/city/', '/conference/theme/', + '/expo/theme/', '/expo/country/', '/expo/city/'] + +class Additional(SimpleAbstract): + priority = 0.5 + + def items(self): + return ['/blogs/', '/news/', '/partners/', '/about/', '/advertising/', '/contacts/'] \ No newline at end of file diff --git a/proj/urls.py b/proj/urls.py index f20bfd65..9cc974e2 100644 --- a/proj/urls.py +++ b/proj/urls.py @@ -1,23 +1,44 @@ # -*- coding: utf-8 -*- from django.conf import settings from django.conf.urls import patterns, include, url -from core.views import PlaceListView, PlacePhotoView, EventSearchView from core.simple_index_view import AdvertisingView, AboutView -from views import MainPageView, MainPageViewTest -from place_exposition.views import PlaceSearchView +from views import MainPageView +from django.contrib.sitemaps import views +import debug_toolbar +from django.views.generic.base import TemplateView -from django.http import HttpResponse +class Robot(TemplateView): + template_name = 'robots.txt' + content_type = 'text/plain' +from django.contrib.sitemaps import Sitemap +from exposition.models import Exposition + +from sitemaps import ExpoCard, ExpoCity, ExpoCountry, ExpoTheme, ExpoTag, ConfCard, ConfCity, ConfCountry, ConfTheme,\ + ConfTag, NewsSiteMap, BlogsSiteMap, Additional, Important + + +sitemaps = { + 'expo_card': ExpoCard(), 'news': NewsSiteMap(), 'blogs': BlogsSiteMap(), 'expo_city': ExpoCity(), \ + 'expo_country': ExpoCountry(), 'expo_theme': ExpoTheme(), \ + 'conference_card': ConfCard(), 'expo_tag': ExpoTag(), 'conference_city': ConfCity(), 'conference_country': ConfCountry(),\ + 'conference_theme': ConfTheme(), 'conference_tag': ConfTag(), 'main': Important(), 'additional': Additional() +} + urlpatterns = patterns('', + #url(r'^__debug__/', include(debug_toolbar.urls)), url(r'^admin/', include('proj.admin_urls')), + #url(r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}), + 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'^$', MainPageView.as_view()), - url(r'^main_page/$', MainPageViewTest.as_view()), url(r'^theme/', include('theme.urls')), url(r'^places/', include('place_exposition.urls')), - url(r'^', include('accounts.urls')), url(r'^', include('exposition.urls')), + url(r'^', include('settings.conference_old_urls')), # conference redirects from old version url(r'^', include('conference.urls')), url(r'^', include('seminar.urls')), url(r'^', include('webinar.urls')), @@ -28,47 +49,30 @@ urlpatterns = patterns('', url(r'^city/', include('city.urls')), url(r'^organiser/', include('organiser.urls')), url(r'^gallery/', include('photologue.client_urls')), - - url(r'^', include('file.urls')), url(r'^', include('django_messages.expomap_urls')), url(r'^messages/', include('django_messages.urls')), - - url(r'^advertising/$', AdvertisingView.as_view()), - url(r'^about/$', AboutView.as_view()), - url(r'^partners/$', AboutView.as_view()), - url(r'^contacts/$', AboutView.as_view()), - #url(r'^events/search/$', EventSearchView.as_view()), - #url(r'^places/search/$', PlaceSearchView.as_view()), - #url(r'^places/(?P.*)/photo/(?P\d+)/$', PlacePhotoView.as_view()), - #url(r'^places/(?P.*)/photo/$', PlacePhotoView.as_view()), - #url(r'^places/(?P.*)/(?P\d+)/$', PlaceListView.as_view()), - #url(r'^places/(?P\d+)/$', PlaceListView.as_view()), - #url(r'^places/(?P.*)/$', PlaceListView.as_view()), - #url(r'^places/$', PlaceListView.as_view()), + url(r'^advertising/$', AdvertisingView.as_view(), {'meta_id':58}), + url(r'^about/$', AboutView.as_view(), {'meta_id':56}), + url(r'^partners/$', AboutView.as_view(), {'meta_id':57}), + url(r'^contacts/$', AboutView.as_view(), {'meta_id':59}), url(r'^social/', include('social.apps.django_app.urls', namespace='social')), url(r'^login/', 'registration.backends.default.views.LoginView'), url(r'^logout/', 'registration.backends.default.views.LogoutView'), - #url(r'^profile/$', 'accounts.views.profile'), url(r'^accounts/', include('registration.backends.default.urls')), - #url(r'^places/$', 'place_exposition.views.catalog'), - #url(r'^places/(?P.*)/(?Pphoto)', 'place_exposition.views.place'), - #url(r'^places/(?P.*)', 'place_exposition.views.place'), - #url(r'^company/(?P.*)', 'core.views.company'), url(r'^', include('password_reset.urls')), url(r'^i18n/', include('django.conf.urls.i18n')), + url(r'^redirect/', include('banners.urls')), #url(r'^social/', include('social_auth.urls')), - - - # admin part - url(r'^search/', include('haystack.urls')), - + url(r'^', include('settings.old_urls')), + #url(r'^search/', include('haystack.urls')), url(r'^', include('service.urls')), - ) + # ajax urls urlpatterns += patterns('', + 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'), url(r'^callback/', 'core.simple_index_view.callback'), @@ -78,17 +82,13 @@ urlpatterns += patterns('', url(r'^search-form/autosearch/exposition/$', 'settings.views.expo_autosearch'), url(r'^search-form/autosearch/place/$', 'settings.views.place_autosearch'), url(r'^search-form/autosearch/company/$', 'settings.views.company_autosearch'), - - - + url(r'^', include('settings.old_urls')), url(r'^', include('accounts.user_catalog_urls')), - ) -""" + if settings.DEBUG: import debug_toolbar urlpatterns += patterns('', url(r'^__debug__/', include(debug_toolbar.urls)), - ) -""" \ No newline at end of file + ) \ No newline at end of file diff --git a/proj/views.py b/proj/views.py index bbc0adc0..86de716f 100644 --- a/proj/views.py +++ b/proj/views.py @@ -8,6 +8,7 @@ from exposition.models import Exposition from theme.models import Theme from news.models import News from article.models import Article +from functions.cache_mixin import JitterCacheMixin, CacheMixin from functions.forms import ThemeSearch, PlaceSearch @@ -16,62 +17,37 @@ from functions.custom_views import ExpoListView from accounts.forms import RegistrationCompleteForm def expo_context(request): - cont = {'theme_search_form': ThemeSearch(), 'search_form': ExpositionSearchForm(), 'expo_catalog': Exposition.catalog, - 'book_aid': settings.BOOKING_AID} + cont = {'theme_search_form': ThemeSearch(), 'expo_catalog': Exposition.catalog, + 'book_aid': settings.BOOKING_AID, 'blogs': Article.objects.main_page_blogs(), + 'news_list': Article.objects.main_page_news(), 'sng_countries': settings.SNG_COUNTRIES + } user = request.user if not user.is_anonymous() and not user.url: cont.update({'reg_complete': RegistrationCompleteForm(instance=user)}) - - + if not request.GET: + cont.update({'search_form': ExpositionSearchForm()}) return cont -class MainPageView(TemplateView): +class MainPageView(JitterCacheMixin,TemplateView): + cache_range = settings.CACHE_RANGE template_name = 'index.html' def get_context_data(self, **kwargs): context = super(MainPageView, self).get_context_data(**kwargs) - events = Exposition.objects.all().order_by('-main_page')[:5] - exposition_themes = Theme.objects.order_by('-main_page').filter(types=Theme.types.exposition)[:6] - conference_themes = Theme.objects.order_by('-main_page').filter(types=Theme.types.conference)[:6] - seminar_themes = Theme.objects.order_by('-main_page').filter(types=Theme.types.seminar)[:6] - news_list = News.objects.order_by('-main_page').all()[:3] - articles = Article.objects.order_by('-main_page').all()[:2] - args = {'events': events, 'exposition_themes': exposition_themes, - 'conference_themes': conference_themes, 'seminar_themes': seminar_themes, - 'news_list': news_list, 'articles': articles, 'search_form': EventSearchForm, - 'search_action': '/events/search/'} + events = Exposition.objects.language().select_related('country', 'city', 'place').filter(main_page=1) + 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] + args = {'events': events, 'exposition_themes': exposition_themes, 'conference_themes': conference_themes, + 'search_form': ExpositionSearchForm, 'search_action': '/expo/search/'} context.update(args) return context -class MainPageViewTest(TemplateView): - template_name = 'client/main_page.html' - - def get_context_data(self, **kwargs): - context = super(MainPageViewTest, self).get_context_data(**kwargs) - events = Exposition.objects.all().order_by('-main_page')[:5] - exposition_themes = Theme.objects.order_by('-main_page').filter(types=Theme.types.exposition)[:6] - conference_themes = Theme.objects.order_by('-main_page').filter(types=Theme.types.conference)[:6] - seminar_themes = Theme.objects.order_by('-main_page').filter(types=Theme.types.seminar)[:6] - news_list = News.objects.order_by('-main_page').all()[:3] - articles = Article.objects.order_by('-main_page').all()[:2] - - args = {'events': events, 'exposition_themes': exposition_themes, - 'conference_themes': conference_themes, 'seminar_themes': seminar_themes, - 'news_list': news_list, 'articles': articles} - - - context.update(args) - - return context - - - class AdvertisingView(TemplateView): template_name = 'simple_pages/advertising.html' diff --git a/registration/backends/default/views.py b/registration/backends/default/views.py index 06e3ac06..b1edd557 100644 --- a/registration/backends/default/views.py +++ b/registration/backends/default/views.py @@ -2,6 +2,7 @@ from django.conf import settings from django.contrib.sites.models import RequestSite from django.contrib.sites.models import Site +from django.utils.translation import ugettext as _ from registration import signals from registration.models import RegistrationProfile @@ -34,7 +35,7 @@ class RegistrationView(BaseRegistrationView): * The creation of the templates ``registration/activation_email_subject.txt`` and - ``registration/activation_email.txt``, which will be used for + ``registration/activation_email.html``, which will be used for the activation email. See the notes for this backends ``register`` method for details regarding these templates. @@ -187,6 +188,35 @@ def RegisterAjaxView(request): # 404 # return HttpResponse('not ajax') +def RegisterReply(request): + if request.GET: + email = request.GET['email'] + try: + user = User.objects.get(username=email) + except User.DoesNotExist: + response = {'errors': {'email': _(u'Пользователя с таким email не существует')}} + return HttpResponse(json.dumps(response), content_type='application/json') + if user.is_active: + response = {'errors': {'email': _(u'Пользователя с таким email уже активирован')}} + return HttpResponse(json.dumps(response), content_type='application/json') + else: + try: + registration_profile = user.registrationprofile_set.all()[0] + except IndexError: + registration_profile = RegistrationProfile.create_profile(user) + if Site._meta.installed: + site = Site.objects.get_current() + else: + site = RequestSite(request) + registration_profile.send_activation_email(site) + response = {'success': True} + return HttpResponse(json.dumps(response), content_type='application/json') + + + else: + return HttpResponse('no data') + + from django.contrib.auth.forms import AuthenticationForm from registration.forms import LoginForm @@ -199,7 +229,7 @@ def LogoutView(request): def LoginView(request): if request.POST: - form = AuthenticationForm(data=request.POST) + form = LoginForm(data=request.POST) #return HttpResponse(form.username) @@ -210,6 +240,8 @@ def LoginView(request): #return HttpResponseRedirect(request.META.get('HTTP_REFERER','/')) else: response={'success':False, 'errors': form.errors} + if getattr(form, 'inactive', None): + response.update({'inactive': True}) return HttpResponse(json.dumps(response), content_type='application/json') @@ -222,8 +254,9 @@ def complete_registration(request): response = {'success': False} form = RegistrationCompleteForm(request.POST, instance=request.user) if form.is_valid(): - form.save() + user = form.save() response['success']=True + response['redirect'] = user.get_permanent_url() else: response['errors'] = form.errors return HttpResponse(json.dumps(response), content_type='application/json') diff --git a/registration/forms.py b/registration/forms.py index 79a25c9e..8c6e718b 100644 --- a/registration/forms.py +++ b/registration/forms.py @@ -127,6 +127,33 @@ class RegistrationFormNoFreeEmail(RegistrationForm): raise forms.ValidationError(_("Registration using free email addresses is prohibited. Please supply a different email address.")) return self.cleaned_data['email'] + +from django.contrib.auth import authenticate class LoginForm(AuthenticationForm): - username = forms.CharField(max_length=254, widget=forms.TextInput(attrs={'placeholder': _(u'Ваш адрес электронной почты')})) - password = forms.CharField(label=_("Password"), widget=forms.PasswordInput(attrs={'placeholder': _(u'Ваш Пароль')})) \ No newline at end of file + inactive = False + def clean(self): + username = self.cleaned_data.get('username') + password = self.cleaned_data.get('password') + data = self.cleaned_data + + if username and password: + self.user_cache = authenticate(username=username, + password=password) + if self.user_cache is None: + + self._errors['password'] = ErrorList([self.error_messages['invalid_login'] % { + 'username': self.username_field.verbose_name + }]) + del data['password'] + + + elif not self.user_cache.is_active: + self._errors['username'] = ErrorList([self.error_messages['inactive']]) + self.inactive = True + + del data['username'] + + self.check_for_test_cookie() + return data + + diff --git a/registration/models.py b/registration/models.py index 4ecdf033..7f0f1509 100644 --- a/registration/models.py +++ b/registration/models.py @@ -2,13 +2,15 @@ import datetime import hashlib import random import re - +from django.core.mail import EmailMessage from django.conf import settings from django.contrib.auth.models import User from django.db import models from django.db import transaction -from django.template.loader import render_to_string +from django.template.loader import render_to_string, get_template +from django.template import Context from django.utils.translation import ugettext_lazy as _ +from email.MIMEImage import MIMEImage try: from django.contrib.auth import get_user_model @@ -232,7 +234,7 @@ class RegistrationProfile(models.Model): text; output longer than one line will be forcibly joined into only a single line. - ``registration/activation_email.txt`` + ``registration/activation_email.html`` This template will be used for the body of the email. These templates will each receive the following context @@ -256,15 +258,33 @@ class RegistrationProfile(models.Model): framework for details regarding these objects' interfaces. """ + user = self.user ctx_dict = {'activation_key': self.activation_key, 'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS, - 'site': site} + 'site': site, + 'user': user} subject = render_to_string('registration/activation_email_subject.txt', ctx_dict) # Email subject *must not* contain newlines subject = ''.join(subject.splitlines()) + + message = get_template('registration/activation_email.html').render(Context(ctx_dict)) + msg = EmailMessage(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email]) + msg.content_subtype = "html" + images =(('/img/logo_reg.png', 'logo'), + ('/img/soc-medias/sm-icon-rss.png', 'rss'), + ('/img/soc-medias/sm-icon-fb.png', 'fb'), + ('/img/soc-medias/sm-icon-lin.png', 'linkedin'), + ('/img/soc-medias/sm-icon-vk.png', 'vk'), + ('/img/soc-medias/sm-icon-twit.png', 'twit'), + ('/img/mail-logo-2.jpg','logo2')) + for img in images: + fp = open(settings.STATIC_ROOT+img[0], 'rb') + msg_img = MIMEImage(fp.read()) + fp.close() + msg_img.add_header('Content-ID', '<'+img[1]+'>') + msg.attach(msg_img) + + msg.send() - message = render_to_string('registration/activation_email.txt', - ctx_dict) - - self.user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL) + #self.user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL) \ No newline at end of file diff --git a/service/forms.py b/service/forms.py index 1f3febd7..1431a76e 100644 --- a/service/forms.py +++ b/service/forms.py @@ -28,16 +28,15 @@ class ServiceForm(forms.Form): url = forms.CharField(label='url', required=False) price = forms.IntegerField(label='Цена', required=False, widget=forms.TextInput(attrs={'placeholder':'Валюта'})) + #price = forms.CharField(label='Цена', required=False, # widget=forms.TextInput(attrs={'placeholder':'Валюта'})) currency_list = [('USD','USD'), ('EUR','EUR'), ('RUB','RUB')] currency = forms.ChoiceField(choices=currency_list) - + type = forms.MultipleChoiceField(label='Тип', choices=[('expo', 'expo'), ('conference', 'conference')]) service_id = forms.CharField(required=False, widget=forms.HiddenInput()) - - def __init__(self, *args, **kwargs): super(ServiceForm, self).__init__(*args, **kwargs) # creates translated form fields, example: name_ru, name_en @@ -76,6 +75,8 @@ class ServiceForm(forms.Form): service.price = data['price'] service.currency = data['currency'] + #data['type'] + fill_with_signal(Service, service, data) diff --git a/service/models.py b/service/models.py index 377f4578..0e5eaeec 100644 --- a/service/models.py +++ b/service/models.py @@ -2,9 +2,10 @@ from django.db import models from hvad.models import TranslatableModel, TranslatedFields, TranslationManager from functions.custom_fields import EnumField +from bitfield import BitField -CURENCIES = ('USD', 'RUB', 'EUR') +CURENCIES = ('', 'USD', 'RUB', 'EUR') @@ -12,12 +13,12 @@ CURENCIES = ('USD', 'RUB', 'EUR') class Service(TranslatableModel): - url = models.SlugField(unique=True) currency = EnumField(values=CURENCIES, blank=True, default='USD') price = models.PositiveIntegerField(blank=True, null=True) params = models.CharField(max_length=255, blank=True) template = models.CharField(max_length=255, blank=True) + type = BitField(flags=['expo', 'conference']) #translated fields translations = TranslatedFields( name = models.CharField(max_length=50), @@ -31,6 +32,7 @@ class Service(TranslatableModel): ) sort = models.PositiveIntegerField(default=0, db_index=True) main_page = models.PositiveIntegerField(default=0, db_index=True) + meta_id = models.IntegerField(null=True) def __unicode__(self): @@ -65,15 +67,20 @@ class AbstractOrder(models.Model): exposition = models.ForeignKey('exposition.Exposition', null=True) conference = models.ForeignKey('conference.Conference', null=True) seminar = models.ForeignKey('seminar.Seminar', null=True) + created = models.DateTimeField(auto_now_add=True) + viewed = models.DateTimeField(null=True, blank=True) class Meta: abstract = True + ordering = ['-created'] class Catalog(AbstractOrder): pass +class BuildStand(AbstractOrder): + pass class Tickets(AbstractOrder): days = models.SmallIntegerField() @@ -81,7 +88,7 @@ class Tickets(AbstractOrder): class Remote(AbstractOrder): interested_participants = models.TextField(blank=True) - additional = models.CharField(max_length=255) + additional = models.CharField(max_length=255, blank=True) class Participation(AbstractOrder): @@ -90,12 +97,12 @@ class Participation(AbstractOrder): company_inf = models.TextField() class Translation(AbstractOrder): - days = models.IntegerField() - hours = models.IntegerField() - fr = models.DateField() - to = models.DateField() - languages = models.TextField() - themes = models.TextField() + days = models.IntegerField(null=True,blank=True) + hours = models.IntegerField(null=True, blank=True) + fr = models.DateField(blank=True) + to = models.DateField(blank=True) + languages = models.TextField(blank=True) + themes = models.TextField(blank=True) class Visit(AbstractOrder): fr = models.DateField() @@ -122,3 +129,15 @@ class Visit(AbstractOrder): excursion = models.BooleanField() notes = models.TextField(blank=True) + +class Advertising(AbstractOrder): + pass + +class CallBack(models.Model): + phone = models.CharField(max_length=30) + person_inf = models.CharField(max_length=255) + created = models.DateTimeField(auto_now_add=True) + viewed = models.DateTimeField(null=True, blank=True) + + class Meta: + ordering = ['-created'] \ No newline at end of file diff --git a/service/order_forms.py b/service/order_forms.py index 8b459adb..319db724 100644 --- a/service/order_forms.py +++ b/service/order_forms.py @@ -2,7 +2,7 @@ from django import forms from django.utils.translation import ugettext as _ from accounts.models import User -from models import Catalog, Tickets, Remote, Participation, Translation, Visit, CURENCIES +from models import Catalog, Tickets, Remote, Participation, Translation, Visit, CURENCIES, Advertising, CallBack, BuildStand from exposition.models import Exposition from conference.models import Conference from seminar.models import Seminar @@ -15,7 +15,7 @@ class AbstractOrderForm(forms.ModelForm): phone = forms.CharField(widget=forms.TextInput(attrs={'placeholder': _(u'Контактный номер телефона')})) person = forms.EmailField(widget=forms.TextInput(attrs={'placeholder': _(u'Электронная почта')})) - currency = forms.CharField(widget=forms.HiddenInput()) + currency = forms.CharField(widget=forms.HiddenInput(), required=False) exposition = forms.CharField(widget=forms.HiddenInput(), required=False) conference = forms.CharField(widget=forms.HiddenInput(), required=False) @@ -89,6 +89,10 @@ class CatalogForm(AbstractOrderForm): class Meta: model = Catalog +class BuildStandForm(AbstractOrderForm): + class Meta: + model = BuildStand + class TicketsForm(AbstractOrderForm): class Meta: @@ -101,7 +105,7 @@ ADDITIONAL_REMOTE_CHOICES = [(_(u'официальный каталог'), _(u' ] class RemoteForm(AbstractOrderForm): - additional = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple(), choices=ADDITIONAL_REMOTE_CHOICES) + additional = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple(), choices=ADDITIONAL_REMOTE_CHOICES, required=False) class Meta: model = Remote @@ -126,12 +130,10 @@ LANGS = [(_(u'Русский'), _(u'Русский'))] from theme.models import Theme class TranslationForm(AbstractOrderForm): - languages = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple(), - choices=LANGS) - themes = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple(), - choices=[(theme.id, theme.id) for theme in Theme.objects.language().filter()]) - fr = forms.DateField(widget=forms.DateInput(attrs={'class': 'date dateFrom', 'placeholder': _(u'дд.мм.гггг')})) - to = forms.DateField(widget=forms.DateInput(attrs={'class': 'date dateTo', 'placeholder': _(u'дд.мм.гггг')})) + languages = forms.CharField(required=False) + themes = forms.CharField(required=False) + fr = forms.DateField(widget=forms.DateInput(attrs={'class': 'date dateFrom', 'placeholder': _(u'дд.мм.гггг')}), required=False) + to = forms.DateField(widget=forms.DateInput(attrs={'class': 'date dateTo', 'placeholder': _(u'дд.мм.гггг')}), required=False) class Meta: model = Translation @@ -195,4 +197,14 @@ class VisitForm(AbstractOrderForm): if not avia_type: return '' else: - return ', '.join(avia_type) \ No newline at end of file + return ', '.join(avia_type) + +class AdvertiseForm(AbstractOrderForm): + action = '/service/com_rek/' + class Meta: + model = Advertising + +class CallBackForm(forms.ModelForm): + class Meta: + model = CallBack + fields=('phone', 'person_inf') \ No newline at end of file diff --git a/service/urls.py b/service/urls.py index bb0f88f7..2508a156 100644 --- a/service/urls.py +++ b/service/urls.py @@ -1,8 +1,18 @@ # -*- coding: utf-8 -*- from django.conf.urls import patterns, include, url -from views import ServiceView +from views import ServiceView, CallBackListView, VisitListView, TranslationListView, AdvertisingListView, \ + ParticipationListView, RemoteListView,TicketsListView, Thanks urlpatterns = patterns('', + url(r'service/thanks/$', Thanks.as_view()), + url(r'service/order/callback/$', CallBackListView.as_view()), + url(r'service/order/visit/$', VisitListView.as_view()), + url(r'service/order/translation/$', TranslationListView.as_view()), + url(r'service/order/advertising/$', AdvertisingListView.as_view()), + url(r'service/order/participation/$', ParticipationListView.as_view()), + url(r'service/order/remote/$', RemoteListView.as_view()), + url(r'service/order/tickets/$', TicketsListView.as_view()), + url(r'service/com_rek/$', 'service.views.advertise'), url(r'service/(?P.*)/$', ServiceView.as_view()), ) diff --git a/service/views.py b/service/views.py index 605a14a2..0670b0ef 100644 --- a/service/views.py +++ b/service/views.py @@ -7,13 +7,14 @@ from haystack.query import EmptySearchQuerySet from django.shortcuts import get_object_or_404 from django.http import Http404 import json -from functions.search_forms import CompanySearchForm +#from functions.search_forms import CompanySearchForm -from order_forms import TranslationForm, CatalogForm, VisitForm, RemoteForm, ParticipationForm, TicketsForm +from order_forms import TranslationForm, CatalogForm, VisitForm, RemoteForm, ParticipationForm, TicketsForm,\ + AdvertiseForm, BuildStandForm order_forms = {'translator': TranslationForm, 'catalog': CatalogForm, 'participation': ParticipationForm, - 'remote': RemoteForm, 'tickets': TicketsForm, 'visit': VisitForm} + 'remote': RemoteForm, 'tickets': TicketsForm, 'visit': VisitForm, 'buildstand': BuildStandForm} class ServiceView(FormView): @@ -34,3 +35,51 @@ class ServiceView(FormView): return service.template + +def advertise(request): + if request.POST: + response = {'success': False} + form = AdvertiseForm(request.POST) + if form.is_valid(): + form.save() + response['success'] = True + else: + response['errors'] = form.errors + + return HttpResponse(json.dumps(response), content_type='application/json') + else: + raise HttpResponse('not ajax') + + +from service.models import CallBack, Visit, Translation, Advertising, Participation, Remote, Tickets + +class AbstractOrderListView(ListView): + template_name = 'admin/service/order_list.html' + paginate_by = 20 + +class CallBackListView(AbstractOrderListView): + model = CallBack + + +class VisitListView(AbstractOrderListView): + model = Visit + + +class TranslationListView(AbstractOrderListView): + model = Translation + +class AdvertisingListView(AbstractOrderListView): + model = Advertising + +class ParticipationListView(AbstractOrderListView): + model = Participation + +class RemoteListView(AbstractOrderListView): + model = Remote + +class TicketsListView(AbstractOrderListView): + model = Tickets + + +class Thanks(TemplateView): + template_name = 'client/service/thank_u_page.html' \ No newline at end of file diff --git a/settings/admin.py b/settings/admin.py index f413e85b..5c0c3f39 100644 --- a/settings/admin.py +++ b/settings/admin.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import json from django.shortcuts import render_to_response from django.http import HttpResponseRedirect, HttpResponse from django.core.context_processors import csrf @@ -56,24 +57,36 @@ from conference.models import Conference from seminar.models import Seminar from webinar.models import Webinar from theme.models import Theme +from article.models import Article import datetime def main_page(request): now = datetime.datetime.now() - expositions = Exposition.objects.filter(main_page__gt=0, data_begin__gte=now) - conferences = Conference.objects.filter(main_page__gt=0, data_begin__gte=now) - seminars = Seminar.objects.filter(main_page__gt=0, data_begin__gte=now) - webinars = Webinar.objects.filter(main_page__gt=0, data_begin__gte=now) + expositions = Exposition.objects.filter(main_page=1) + conferences = Conference.objects.filter(main_page=1) + seminars = Seminar.objects.filter(main_page=1) + webinars = Webinar.objects.filter(main_page=1) events = {'expositions':expositions, 'conferences': conferences, 'seminars':seminars, 'webinars': webinars} exposition_themes = Theme.objects.filter(main_page__gt=0, types=Theme.types.exposition) confrence_themes = Theme.objects.filter(main_page__gt=0, types=Theme.types.conference) seminar_themes = Theme.objects.filter(main_page__gt=0, types=Theme.types.seminar) + news = Article.objects.news().filter(main_page=1) + blogs = Article.objects.blogs().filter(main_page=1) themes = {'exposition_themes': exposition_themes, 'conference_themes': confrence_themes, 'seminar_themes':seminar_themes} - args = {'event_form':MainPageEvent(initial=events), 'theme_form':MainPageThemes(initial=themes), 'article_form':MainPageArticle(), - 'news_form':MainPageNews(), 'photoreport_form':MainPagePhotoreport(),} + + news_form = MainPageNews(initial={'main_page_news':','.join(['%d'%item.id for item in news])}) + a = [{'id': int(item.id), 'text': item.main_title} for item in news] + news_form.fields['main_page_news'].widget.attrs['data-init-text'] = json.dumps(a) + article_form = MainPageArticle(initial={'article' : blogs}) + + event_data = {'expositions': ','.join(['%s:%s'%(item.id, item.name) for item in expositions])} + event_form = MainPageEvent(initial=event_data) + args = {'event_form' : event_form, 'theme_form' : MainPageThemes(initial=themes), + 'article_form' : article_form, + 'news_form' : news_form, 'photoreport_form' : MainPagePhotoreport(),} args.update(csrf(request)) return render_to_response('admin/settings/main_page.html', args) \ No newline at end of file diff --git a/settings/admin_urls.py b/settings/admin_urls.py index e857b268..fb38fbeb 100644 --- a/settings/admin_urls.py +++ b/settings/admin_urls.py @@ -7,6 +7,6 @@ urlpatterns = patterns('settings.admin', url(r'^main-page/photoreports/$', 'handle_photoreports'), url(r'^main-page/themes/$', 'handle_themes'), url(r'^main-page/news/$', 'handle_news'), - url(r'^main-page/articles/$', 'handle_articles'), + url(r'^main-page/blogs/$', 'handle_articles'), url(r'^$', 'change_settings'), ) diff --git a/settings/conference_old_urls.py b/settings/conference_old_urls.py new file mode 100644 index 00000000..fa50b3d2 --- /dev/null +++ b/settings/conference_old_urls.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +from django.conf.urls import patterns, include, url +from django.http import HttpResponse +from django.views.decorators.cache import cache_page +from redirect_views import old_redirect, old_profile + + +urlpatterns = patterns('', + url(r'/rubricator.php?result_type=conference$', old_redirect, {'redirect_url': '/conference/'}), #??? + # city + url(r'^conference/city-(?P.*)/year-(?P\d+)/month-(?P.*)$', old_redirect, {'redirect_url': '/conference/city/{city}/{year}/{month}/'}), + url(r'^conference/city-(?P.*)/year-(?P\d+)/$', old_redirect, {'redirect_url': '/conference/city/{city}/{year}/'}), + url(r'^conference/city-(?P.*)/$', old_redirect, {'redirect_url': '/conference/city/{city}/'}), + #url(r'^conference/(?P.*)/$', old_redirect, {'redirect_url': '/conference/city/{city}/'}), # перенести + # country + url(r'^conference/country-(?P.*)/year-(?P\d+)/month-(?P.*)$', old_redirect, {'redirect_url': '/conference/country/{country}/{year}/{month}/'}), + url(r'^conference/country-(?P.*)/year-(?P\d+)/$', old_redirect, {'redirect_url': '/conference/country/{country}/{year}/'}), + url(r'^conference/country-(?P.*)/$', old_redirect, {'redirect_url': '/conference/country/{country}/'}), + #url(r'/conference/(?P.*)/$', old_redirect, {'redirect_url': '/conference/country/{country}/'}), # перенести + # theme + url(r'^conference/theme-(?P.*)/year-(?P\d+)/month-(?P.*)/$', old_redirect, {'redirect_url': '/conference/theme/{theme}/{year}/{month}/'}), + url(r'^conference/theme-(?P.*)/year-(?P\d+)/$', old_redirect, {'redirect_url': '/conference/theme/{theme}/{year}/'}), + url(r'^conference/theme-(?P.*)/city-(?P.*)/year-(?P\d+)/month-/$', old_redirect, {'redirect_url': '/conference/theme/{theme}/city/{city}/{year}/'}), + url(r'^conference/theme-(?P.*)/city-(?P.*)/year-(?P\d+)/$', old_redirect, {'redirect_url': '/conference/theme/{theme}/city/{city}/{year}/'}), + url(r'^conference/theme-(?P.*)/city-(?P.*)/$', old_redirect, {'redirect_url': '/conference/theme/{theme}/city/{city}/'}), + #url(r'^conference/theme/(?P.*)/$', old_redirect, {'redirect_url': '/conference/theme/{theme}/'}), # перенести + url(r'^conference/theme-(?P.*)/$', old_redirect, {'redirect_url': '/conference/theme/{theme}/'}), + ) diff --git a/settings/forms.py b/settings/forms.py index cdff1b1f..e0aed057 100644 --- a/settings/forms.py +++ b/settings/forms.py @@ -77,25 +77,53 @@ from article.models import Article import datetime +class MainPageEvent(forms.Form): + expositions = forms.CharField(label=u'Выставки', widget=forms.HiddenInput(), required=False) + conferences = forms.CharField(label=u'Конференции', widget=forms.HiddenInput(), required=False) + + def save(self): + data = self.cleaned_data + expositions = data['expositions'] + conferences = data['conferences'] + Exposition.objects.filter(main_page=1).update(main_page=0) + Exposition.objects.filter(id__in=expositions).update(main_page=1) + #Conference.objects.filter(main_page=1).update(main_page=0) + #Conference.update(main_page=1) + + + def clean_expositions(self): + expositions = self.cleaned_data.get('expositions') + if expositions: + res = [] + for id in expositions.split(','): + try: + res.append(int(id)) + except: + continue + return res + else: + return [] + +""" class MainPageEvent(forms.Form): def __init__(self, *args, **kwargs): super(MainPageEvent, self).__init__(*args, **kwargs) now = datetime.datetime.now self.fields['expositions' ] = forms.ModelMultipleChoiceField( - queryset=Exposition.objects.filter(data_begin__gte=now), + queryset=Exposition.objects.all(), required=False ) self.fields['conferences' ] = forms.ModelMultipleChoiceField( - queryset=Conference.objects.filter(data_begin__gte=now), + queryset=Conference.objects.all(), required=False ) self.fields['seminars' ] = forms.ModelMultipleChoiceField( - queryset=Seminar.objects.filter(data_begin__gte=now), + queryset=Seminar.objects.all(), required=False ) self.fields['webinars' ] = forms.ModelMultipleChoiceField( - queryset=Webinar.objects.filter(data_begin__gte=now), + queryset=Webinar.objects.all(), required=False ) def save(self): @@ -112,26 +140,27 @@ class MainPageEvent(forms.Form): seminars.update(main_page=1) Webinar.objects.all().update(main_page=0) webinars.update(main_page=1) +""" class MainPageThemes(forms.Form): exposition_themes = forms.ModelMultipleChoiceField(queryset=Theme.objects.filter(types=Theme.types.exposition), required=False) conference_themes = forms.ModelMultipleChoiceField(queryset=Theme.objects.filter(types=Theme.types.conference), required=False) - seminar_themes = forms.ModelMultipleChoiceField(queryset=Theme.objects.filter(types=Theme.types.seminar), - required=False) + #seminar_themes = forms.ModelMultipleChoiceField(queryset=Theme.objects.filter(types=Theme.types.seminar), + # required=False) def save(self): data = self.cleaned_data exposition_themes = data['exposition_themes'] conference_themes = data['conference_themes'] - seminar_themes = data['seminar_themes'] + #seminar_themes = data['seminar_themes'] Theme.objects.filter(types=Theme.types.exposition).update(main_page=0) Theme.objects.filter(types=Theme.types.conference).update(main_page=0) - Theme.objects.filter(types=Theme.types.seminar).update(main_page=0) + #Theme.objects.filter(types=Theme.types.seminar).update(main_page=0) exposition_themes.update(main_page=1) conference_themes.update(main_page=1) - seminar_themes.update(main_page=1) + #seminar_themes.update(main_page=1) @@ -146,20 +175,33 @@ class MainPagePhotoreport(forms.Form): class MainPageNews(forms.Form): - news = forms.ModelMultipleChoiceField(queryset=News.objects.all()) + main_page_news = forms.CharField(label=u'Новости', widget=forms.HiddenInput(), required=False,) def save(self): data = self.cleaned_data - news = data['news'] + news = data['main_page_news'] + Article.objects.news().exclude(id__in=[item.id for item in news]).update(main_page=0) news.update(main_page=1) + def clean_main_page_news(self): + news = self.cleaned_data['main_page_news'] + if news: + news = news.split(',') + qs = Article.objects.news().filter(id__in=news) + else: + qs = Article.objects.none() + return qs + + + class MainPageArticle(forms.Form): - article = forms.ModelMultipleChoiceField(queryset=Article.objects.all()) + article = forms.ModelMultipleChoiceField(queryset=Article.objects.blogs(), required=False, + widget=forms.SelectMultiple(attrs={'style': 'width: 100%;'})) def save(self): data = self.cleaned_data - articles = data['articles'] - articles.update(main_page=1) - def save(self): - pass \ No newline at end of file + articles = data['article'] + + Article.objects.blogs().exclude(id__in=[item.id for item in articles]).update(main_page=0) + articles.update(main_page=1) \ No newline at end of file diff --git a/settings/old_urls.py b/settings/old_urls.py new file mode 100644 index 00000000..e56d8806 --- /dev/null +++ b/settings/old_urls.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +from django.conf.urls import patterns, include, url +from django.http import HttpResponse +from django.views.decorators.cache import cache_page +from redirect_views import old_redirect, old_profile +def test(request): + return HttpResponse('test') + + +urlpatterns = patterns('', + # service + url(r'^rubricator.php/?result_type=expo$', old_redirect, {'redirect_url': '/expo/'}), #??? + url(r'^serv-zaoch-info.php$', old_redirect, {'redirect_url': '/service/remote/'}), + url(r'^serv-visit-info.php$', old_redirect, {'redirect_url': '/service/visit/'}), + url(r'^serv-bilet-info.php$', old_redirect, {'redirect_url': '/service/tickets/'}), + url(r'^serv-translator-info.php$', old_redirect, {'redirect_url': '/service/translator/'}), + url(r'^content.php/coID/(?P.*)/perevodchiki-(?P.*)/$', old_redirect, {'redirect_url': '/service/translator/'}), + url(r'^content.php/coID/(?P.*)/perevodchiki-(?P.*)$', old_redirect, {'redirect_url': '/service/translator/'}), + + url(r'^(?P.*)/(?P.*)/buildstand.html$', old_redirect, {'redirect_url': '{event_catalog}{event_url}/service/participation/'}), + url(r'^(?P.*)/(?P.*)/bilet.html$', old_redirect, {'redirect_url': '{event_catalog}{event_url}/service/tickets/'}), + url(r'^(?P.*)/(?P.*)/zaoch.html$', old_redirect, {'redirect_url': '{event_catalog}{event_url}/service/remote/'}), + url(r'^(?P.*)/(?P.*)/translator.html$', old_redirect, {'redirect_url': '{event_catalog}{event_url}/service/translator/'}), + url(r'^(?P.*)/(?P.*)/visit.html$', old_redirect, {'redirect_url': '{event_catalog}{event_url}/service/visit/'}), + url(r'^(?P.*)/(?P.*)/uchastie.html$', old_redirect, {'redirect_url': '{event_catalog}{event_url}/service/participation/'}), + url(r'^(?P.*)/(?P.*)/ad.html$', old_redirect, {'redirect_url': '{event_catalog}{event_url}/service/participation/'}), + url(r'^(?P.*)/(?P.*)/mobilestand.html$', old_redirect, {'redirect_url': '{event_catalog}{event_url}/service/participation/'}), + + # company + url(r'^company/(?P.*)$', old_redirect, {'redirect_url': '/members/{company}/'}), + # articles and news + url(r'^articles.php$', old_redirect, {'redirect_url': '/blogs/'}), + url(r'^news.php$', old_redirect, {'redirect_url': '/news/'}), + url(r'^news.php/news/archive/', old_redirect, {'redirect_url': '/news/'}), + url(r'^article_info.php/articles_id/(?P
\d+)/(?P.*)$', old_redirect, {'redirect_url': '/blogs/{article}/'}), + url(r'^news.php/news_id/(?P
\d+)/(?P.*)$', old_redirect, {'redirect_url': '/news/{article}/'}), + # users + url(r'^users/(?P.*)$', old_redirect, {'redirect_url': '/{user}/'}), + url(r'^account_edit.php$', old_profile), + url(r'^myexpo.php$', old_redirect, {'redirect_url': '/profile/calendar/'}), + url(r'^newsletter2.php?email=(?P.*)$', old_redirect, {'redirect_url': '/profile/settings/'}), + url(r'^account_password.php$', old_redirect, {'redirect_url': '/profile/settings/'}), + #url(r'^serv-personal-info.php$', old_redirect, {'redirect_url': '/service/staff/'}), + # EXPO + # city + url(r'^catalog/city-(?P)/theme-(?P.*)/year-(?P\d+)/month-/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/city/{city}/{year}/'}), + url(r'^catalog/city-(?P.*)/theme-(?P.*)/year-(?P\d+)/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/city/{city}/{year}/'}), + url(r'^catalog/city-(?P.*)/theme-(?P.*)/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/city/{city}/'}), + url(r'^catalog/city-(?P.*)/year-(?P\d+)/month-(?P.*)/$', old_redirect, {'redirect_url': '/expo/city/{city}/{year}/{month}'}), + url(r'^catalog/city/(?P.*)/year-(?P\d+)/month-(?P.*)/$', old_redirect, {'redirect_url': '/expo/city/{city}/{year}/{month}'}), + url(r'^catalog/city-(?P.*)/year-(?P\d+)/$', old_redirect, {'redirect_url': '/expo/city/{city}/{year}'}), + url(r'^catalog/city/(?P.*)/year-(?P\d+)/$', old_redirect, {'redirect_url': '/expo/city/{city}/{year}'}), + url(r'^catalog/city-(?P.*)/$', old_redirect, {'redirect_url': '/expo/city/{city}/'}), + # country + url(r'^catalog/country-(?P)/theme-(?P.*)/year-(?P\d+)/month-/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/country/{country}/{year}/'}), + url(r'^catalog/country-(?P.*)/theme-(?P.*)/year-(?P\d+)/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/country/{country}/{year}/'}), + url(r'^catalog/country-(?P.*)/theme-(?P.*)/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/country/{country}/'}), + url(r'^catalog/country-(?P.*)/year-(?P\d+)/month-(?P.*)/$', old_redirect, {'redirect_url': '/expo/country/{country}/{year}/{month}/'}), + url(r'^catalog/country/(?P.*)/year-(?P\d+)/month-(?P.*)/$', old_redirect, {'redirect_url': '/expo/country/{country}/{year}/{month}/'}), + url(r'^catalog/country-(?P.*)/year-(?P\d+)/$', old_redirect, {'redirect_url': '/expo/country/{country}/{year}/'}), + url(r'^catalog/country/(?P.*)/year-(?P\d+)/$', old_redirect, {'redirect_url': '/expo/country/{country}/{year}/'}), + url(r'^catalog/country/(?P.*)/$', old_redirect, {'redirect_url': '/expo/country/{country}/'}), + url(r'^catalog/country-(?P.*)/$', old_redirect, {'redirect_url': '/expo/country/{country}/'}), + url(r'^catalog/country/$', old_redirect, {'redirect_url': '/expo/country/'}), + # theme + url(r'^catalog/theme-(?P.*)/year-(?P\d+)/month-(?P.*)/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/{year}/{month}/'}), + url(r'^catalog/theme-(?P.*)/year-(?P\d+)/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/{year}/'}), + url(r'^catalog/theme-(?P.*)/city-(?P)/year-(?P\d+)/month-/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/city/{city}/{year}/'}), + url(r'^catalog/theme-(?P.*)/city-(?P.*)/year-(?P\d+)/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/city/{city}/{year}/'}), + url(r'^catalog/theme-(?P.*)/city-(?P.*)/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/city/{city}/'}), + url(r'^catalog/theme-(?P.*)/country-(?P)/year-(?P\d+)/month-/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/country/{country}/{year}/'}), + url(r'^catalog/theme-(?P.*)/country-(?P.*)/year-(?P\d+)/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/country/{country}/{year}/'}), + url(r'^catalog/theme-(?P.*)/country-(?P.*)/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/country/{country}/'}), + url(r'^catalog/theme/(?P.*)/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/'}), + url(r'^catalog/theme-(?P.*)/$', old_redirect, {'redirect_url': '/expo/theme/{theme}/'}), + url(r'^catalog/theme/$', old_redirect, {'redirect_url': '/expo/theme/'}), + # tag + url(r'^tag/(?P.*)/$', old_redirect, {'redirect_url': '/expo/tag/{tag}/'}), + + url(r'^catalog/(?P.*)/$', old_redirect, {'redirect_url': '/expo/city/{city}/'}), + url(r'^catalog/$', old_redirect, {'redirect_url': '/expo/city/'}), + # tag + + url(r'^(?P.*)/(?P.*).html$', old_redirect, {'redirect_url': '{event_catalog}{event_url}/'}), +) diff --git a/settings/redirect_views.py b/settings/redirect_views.py new file mode 100644 index 00000000..99c9f2cd --- /dev/null +++ b/settings/redirect_views.py @@ -0,0 +1,97 @@ +from django.http import HttpResponseRedirect, HttpResponse, Http404, HttpResponsePermanentRedirect +from django.shortcuts import get_object_or_404 +from city.models import City +from country.models import Country +from theme.models import Theme, Tag +from exposition.models import Exposition +from conference.models import Conference +from company.models import Company +from article.models import Article +from accounts.models import User + + +class RedirectMixin(object): + model = None + + def get_object_url(self, key, value): + Model = self.model + + try: + obj = Model.objects.get(old_url=value) + except: + obj = get_object_or_404(Model, url=value) + if obj: + return {key: obj.url} + else: + raise Http404 + +class CityRedirect(RedirectMixin): + model = City + +class CountryRedirect(RedirectMixin): + model = Country + +class ThemeRedirect(RedirectMixin): + model = Theme + +class TagRedirect(RedirectMixin): + model = Tag + +class CompanyRedirect(RedirectMixin): + model = Company + + + +class EventRedirect(object): + + def get_object_url(self,key, value): + + try: + obj = Exposition.objects.get(old_url=value) + except Exposition.DoesNotExist: + obj = Exposition.objects.safe_get(url=value) + + if not obj: + try: + obj = Conference.objects.get(old_url=value) + except Conference.DoesNotExist: + obj = Conference.objects.safe_get(url=value) + if obj: + return {'event_url': obj.url, 'event_catalog': obj.catalog} + else: + raise Http404 + +class ArticleRedirect(object): + def get_object_url(self,key, value): + obj = get_object_or_404(Article, id=value) + return {key: obj.slug} + +class UserRedirect(object): + def get_object_url(self,key, value): + obj = get_object_or_404(User, url=value) + return {key: obj.url} + + +old_params = {'city': CityRedirect, 'country': CountryRedirect, 'theme': ThemeRedirect, 'tag': TagRedirect, + 'event': EventRedirect, 'company': Company, 'article': ArticleRedirect, 'user': UserRedirect} + +def old_redirect(request, *args, **kwargs): + redirect = kwargs.get('redirect_url') + params = dict(kwargs) + updates = {} + for key, value in params.iteritems(): + if key in old_params: + redirect_obj = old_params[key]() + updates.update(redirect_obj.get_object_url(key, value)) + + + params.update(updates) + redirect = redirect.format(**params) + return HttpResponsePermanentRedirect(redirect) + +def old_profile(request): + user = request.user + if user.is_authenticated(): + return HttpResponseRedirect('/%s/'%user.url) + else: + raise Http404 \ No newline at end of file diff --git a/settings/templatetags/tempalte_tags.py b/settings/templatetags/tempalte_tags.py index 5061e270..aa540f89 100644 --- a/settings/templatetags/tempalte_tags.py +++ b/settings/templatetags/tempalte_tags.py @@ -11,8 +11,10 @@ register = template.Library() class Date(template.Node): - def __init__(self): - self.now = datetime.datetime.today() + def __init__(self, reverse=False): + date = datetime.datetime.today().replace(day=1) + self.now = date + self.reverse = reverse def render(self, context): @@ -26,16 +28,35 @@ class Date(template.Node): date = self.now month = monthes[date.month] month_period =[{'month_url': month['url'], 'name':month['name'], 'date':date}] - for i in range(5): - try: - date = date.replace(month=date.month+1) - except ValueError: - if date.month == 12: - date = date.replace(year=date.year+1, month=1) + if not self.reverse: + for i in range(5): + try: + date = date.replace(month=date.month+1) + except ValueError: + if date.month == 12: + date = date.replace(year=date.year+1, month=1) + else: + raise + month = monthes.get(date.month) + month_period.append({'month_url': month['url'], 'name':month['name'], 'date':date}) + else: + for i in range(5): + month = date.month - 1 + if month == 0: + date = date.replace(year=date.year-1, month=12) else: - raise - month = monthes.get(date.month) - month_period.append({'month_url': month['url'], 'name':month['name'], 'date':date}) + date = date.replace(month=date.month-1) + """ + try: + date = date.replace(month=date.month-1) + except ValueError: + if date.month == 0: + date = date.replace(year=date.year-1, month=12) + else: + raise + """ + month = monthes.get(date.month) + month_period.append({'month_url': month['url'], 'name':month['name'], 'date':date}) context['monthes_period'] = month_period return u"" @@ -47,6 +68,9 @@ def get_date(parser, token): return Date() +def get_date_reverse(parser, token): + return Date(reverse=True) + class SetVarNode(template.Node): def __init__(self, var_name, var_value): @@ -72,4 +96,5 @@ def set_var(parser, token): register.tag('set', set_var) register.tag('get_date', get_date) +register.tag('get_date_reverse', get_date_reverse) diff --git a/settings/templatetags/template_filters.py b/settings/templatetags/template_filters.py index aad5a748..37d44578 100644 --- a/settings/templatetags/template_filters.py +++ b/settings/templatetags/template_filters.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from django import template +import base64 import phonenumbers import datetime, random from datetime import timedelta @@ -231,7 +232,7 @@ def next_monthes(value): @register.filter def get_rus_day(date): - days = {1: u'Пн', 2: u'Вт', 3: u'Ср', 4: u'Чт', 5: u'Пт', 6: u'Сб', 0: u'Вс',} + days = {0: u'Пн', 1: u'Вт', 2: u'Ср', 3: u'Чт', 4: u'Пт', 5: u'Сб', 6: u'Вс',} return days.get(date.weekday(), '') @@ -243,3 +244,36 @@ def in_events(day, events): return False +@register.filter +def base64_encode(value): + return base64.b64encode(value) + + +@register.filter +def generate_countries_list(value): + values = value.split(';') + values.sort() + if len(values) >= 2: + ul1 = values[::3] + ul2 = values[1::3] + ul3 = values[2::3] + elif len(values) >= 2: + ul1 = values[::2] + ul2 = values[1::2] + ul3 = [] + else: + ul1 = values + ul2 = [] + ul3 = [] + + ul1_html = ''.join(['
  • %s
  • '%i for i in ul1]) + ul2_html = ''.join(['
  • %s
  • '%i for i in ul2]) + ul3_html = ''.join(['
  • %s
  • '%i for i in ul3]) + + ul1 ='
      ' + ul1_html + '
    ' + ul2 ='
      ' + ul2_html + '
    ' + ul3 ='
      ' + ul3_html + '
    ' + + + + return ul1+ul2+ul3 \ No newline at end of file diff --git a/settings/views.py b/settings/views.py index 3b56d8a6..d9435df6 100644 --- a/settings/views.py +++ b/settings/views.py @@ -52,10 +52,7 @@ def search_autocomplete(request): objects = areas + countries + cities return HttpResponse(json.dumps(objects), content_type='application/json') if form == 'subj': - objects = [{'text': get_by_lang(item, 'name', lang), 'id':item.pk, 'name': item.form_name} for item in SearchQuerySet().models(Theme, Tag).autocomplete(content_auto=term)] - #themes = [{'text':item.name, 'id':item.id, 'name':'th'} for item in Theme.objects.filter(translations__name__contains=term)] - #tags = [{'text':item.name, 'id':item.id, 'name':'tg'} for item in Tag.objects.filter(translations__name__contains=term)] - #objects = themes + tags + 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') else: return HttpResponse("Don't implemented yet") @@ -95,8 +92,11 @@ def expo_autosearch(request): lang = translation.get_language() term = request.GET['term'] qs = SearchQuerySet().models(Exposition, Theme, Tag).autocomplete(content_auto=term).order_by('text') - result = [{'cat': get_by_lang(item, 'catalog_name', lang), 'text': get_by_lang(item, 'name', lang), 'url':item.url, - 'id':item.pk, 'name': item.form_name} for item in qs] + 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 qs] result = sorted(result, key=lambda x:x['cat'], reverse=True) return HttpResponse(json.dumps(result), content_type='application/json') else: diff --git a/static/custom_js/main.js b/static/custom_js/main.js index b9989d43..3c301189 100644 --- a/static/custom_js/main.js +++ b/static/custom_js/main.js @@ -86,6 +86,30 @@ function postTimetable(data, textStatus){ } } +function postStat(data, textStatus){ + if(data.success){ + location.reload; + } + else{ + $.each(data.errors, function(field_name, errors){ + $('#id_'+field_name).parent().parent().addClass('error'); + }) + } + /* + if (data instanceof Object){ + $.each(data, function(field_name, errors){ + $('#id_'+field_name).parent().parent().addClass('error'); + }) + } + else{ + $('#stat_modal table tbody').html(data); + $('#stat_form')[0].reset(); + $('#stat_form .control-group').removeClass('error'); + $('#close_stat').click(); + } + */ + } + $(document).ready(function(){ @@ -250,7 +274,52 @@ $(document).ready(function(){ }); + $('#id_main_page_news').select2({ + placeholder: "Новости", + multiple: true, + width: '100%', + ajax: { + + url: "/admin/ajax/get-news/", + dataType: "json", + quietMillis: 200, + data: function(term, page){ + + 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 text = $(element).attr('data-init-text'); + var data = $.parseJSON(text); + console.log(data); + /* + var data = []; + $(element.val().split(",")).each(function(i) { + var item = this.split(':'); + data.push({ + id: item[0], + text: item[1] + }); + }); + console.log(data) + */ + callback(data); + + } + }); // selects $('#id_tag').select2({ @@ -350,6 +419,29 @@ $(document).ready(function(){ });//end get });//end change + $('#stat_form').on('submit', function(e){//submit(function(){ + e.preventDefault(); + var url = '/admin/ajax_post_stat/' + $('#obj_id').val() + '/'; + console.log(url) + var formData = $(this).serialize(); + + $.ajax({ + url: url, //server script to process data + type: 'GET', + + //Ajax events + success: postStat, + error: function(){ alert('error'); }, + // Form data + data: formData, + //Options to tell JQuery not to process data or worry about content-type + cache: false, + contentType: false, + processData: false + });//end ajax + + }); // end submit + $('#timetable_form').on('submit', function(e){//submit(function(){ e.preventDefault(); tinyMCE.triggerSave(); diff --git a/static/img/1.png b/static/img/1.png new file mode 100644 index 00000000..b4d8164f Binary files /dev/null and b/static/img/1.png differ diff --git a/static/img/2.png b/static/img/2.png new file mode 100644 index 00000000..42786c85 Binary files /dev/null and b/static/img/2.png differ diff --git a/static/img/about_pic.png b/static/img/about_pic.png new file mode 100644 index 00000000..913bd16f Binary files /dev/null and b/static/img/about_pic.png differ diff --git a/static/img/add_link_text.png b/static/img/add_link_text.png new file mode 100644 index 00000000..74974dd2 Binary files /dev/null and b/static/img/add_link_text.png differ diff --git a/static/img/add_pic_block_bg.png b/static/img/add_pic_block_bg.png new file mode 100644 index 00000000..64a30668 Binary files /dev/null and b/static/img/add_pic_block_bg.png differ diff --git a/static/img/add_pic_block_bg1.png b/static/img/add_pic_block_bg1.png new file mode 100644 index 00000000..74debc37 Binary files /dev/null and b/static/img/add_pic_block_bg1.png differ diff --git a/static/img/add_pic_block_bg2.png b/static/img/add_pic_block_bg2.png new file mode 100644 index 00000000..e515e3b1 Binary files /dev/null and b/static/img/add_pic_block_bg2.png differ diff --git a/static/img/ag-bg.png b/static/img/ag-bg.png new file mode 100644 index 00000000..c64dc99e Binary files /dev/null and b/static/img/ag-bg.png differ diff --git a/static/img/ajax-loader.gif b/static/img/ajax-loader.gif new file mode 100644 index 00000000..67d23f3c Binary files /dev/null and b/static/img/ajax-loader.gif differ diff --git a/static/img/approved-logo.png b/static/img/approved-logo.png new file mode 100644 index 00000000..6f28d68d Binary files /dev/null and b/static/img/approved-logo.png differ diff --git a/static/img/blog_pic.jpg b/static/img/blog_pic.jpg new file mode 100644 index 00000000..3368faaa Binary files /dev/null and b/static/img/blog_pic.jpg differ diff --git a/static/img/blog_pic1.jpg b/static/img/blog_pic1.jpg new file mode 100644 index 00000000..c29c191c Binary files /dev/null and b/static/img/blog_pic1.jpg differ diff --git a/static/img/blog_pic2.jpg b/static/img/blog_pic2.jpg new file mode 100644 index 00000000..edbc04b7 Binary files /dev/null and b/static/img/blog_pic2.jpg differ diff --git a/static/img/clock.png b/static/img/clock.png new file mode 100644 index 00000000..5620e403 Binary files /dev/null and b/static/img/clock.png differ diff --git a/static/img/female.png b/static/img/female.png new file mode 100644 index 00000000..2ae0db82 Binary files /dev/null and b/static/img/female.png differ diff --git a/static/img/libk_bg.png b/static/img/libk_bg.png new file mode 100644 index 00000000..15b34716 Binary files /dev/null and b/static/img/libk_bg.png differ diff --git a/static/img/logo_reg.png b/static/img/logo_reg.png new file mode 100644 index 00000000..fce2e4a8 Binary files /dev/null and b/static/img/logo_reg.png differ diff --git a/static/img/mail-logo-2.jpg b/static/img/mail-logo-2.jpg new file mode 100644 index 00000000..39f9d896 Binary files /dev/null and b/static/img/mail-logo-2.jpg differ diff --git a/static/img/male.png b/static/img/male.png new file mode 100644 index 00000000..42f3832b Binary files /dev/null and b/static/img/male.png differ diff --git a/static/img/map.png b/static/img/map.png new file mode 100644 index 00000000..e006e14c Binary files /dev/null and b/static/img/map.png differ diff --git a/static/img/no-logo.jpg b/static/img/no-logo.jpg new file mode 100644 index 00000000..af5abc3c Binary files /dev/null and b/static/img/no-logo.jpg differ diff --git a/static/img/no-logo.png b/static/img/no-logo.png new file mode 100644 index 00000000..a29836ad Binary files /dev/null and b/static/img/no-logo.png differ diff --git a/static/img/pic1.jpg b/static/img/pic1.jpg new file mode 100644 index 00000000..c016064d Binary files /dev/null and b/static/img/pic1.jpg differ diff --git a/static/img/pic10.jpg b/static/img/pic10.jpg new file mode 100644 index 00000000..d9e0ee87 Binary files /dev/null and b/static/img/pic10.jpg differ diff --git a/static/img/pic11.jpg b/static/img/pic11.jpg new file mode 100644 index 00000000..ba3e75c3 Binary files /dev/null and b/static/img/pic11.jpg differ diff --git a/static/img/pic12.png b/static/img/pic12.png new file mode 100644 index 00000000..6fe246bb Binary files /dev/null and b/static/img/pic12.png differ diff --git a/static/img/pic13.jpg b/static/img/pic13.jpg new file mode 100644 index 00000000..ca44f19a Binary files /dev/null and b/static/img/pic13.jpg differ diff --git a/static/img/pic14.jpg b/static/img/pic14.jpg new file mode 100644 index 00000000..61f2456a Binary files /dev/null and b/static/img/pic14.jpg differ diff --git a/static/img/pic15.jpg b/static/img/pic15.jpg new file mode 100644 index 00000000..8e3e85fe Binary files /dev/null and b/static/img/pic15.jpg differ diff --git a/static/img/pic16.jpg b/static/img/pic16.jpg new file mode 100644 index 00000000..a0c2420e Binary files /dev/null and b/static/img/pic16.jpg differ diff --git a/static/img/pic2.jpg b/static/img/pic2.jpg new file mode 100644 index 00000000..0012dcc5 Binary files /dev/null and b/static/img/pic2.jpg differ diff --git a/static/img/pic3.jpg b/static/img/pic3.jpg new file mode 100644 index 00000000..6963b2fa Binary files /dev/null and b/static/img/pic3.jpg differ diff --git a/static/img/pic4.jpg b/static/img/pic4.jpg new file mode 100644 index 00000000..c9870741 Binary files /dev/null and b/static/img/pic4.jpg differ diff --git a/static/img/pic5.jpg b/static/img/pic5.jpg new file mode 100644 index 00000000..8fafa1a0 Binary files /dev/null and b/static/img/pic5.jpg differ diff --git a/static/img/pic6.jpg b/static/img/pic6.jpg new file mode 100644 index 00000000..3259b33b Binary files /dev/null and b/static/img/pic6.jpg differ diff --git a/static/img/pic7.jpg b/static/img/pic7.jpg new file mode 100644 index 00000000..a494ce73 Binary files /dev/null and b/static/img/pic7.jpg differ diff --git a/static/img/pic8.jpg b/static/img/pic8.jpg new file mode 100644 index 00000000..8f41ae64 Binary files /dev/null and b/static/img/pic8.jpg differ diff --git a/static/img/pic8.png b/static/img/pic8.png new file mode 100644 index 00000000..6fc26cb7 Binary files /dev/null and b/static/img/pic8.png differ diff --git a/static/img/pic9.jpg b/static/img/pic9.jpg new file mode 100644 index 00000000..cfaa2219 Binary files /dev/null and b/static/img/pic9.jpg differ diff --git a/static/img/pin.png b/static/img/pin.png new file mode 100644 index 00000000..b0dba26d Binary files /dev/null and b/static/img/pin.png differ diff --git a/static/img/search-bg.jpg b/static/img/search-bg.jpg new file mode 100644 index 00000000..6c1828d1 Binary files /dev/null and b/static/img/search-bg.jpg differ diff --git a/static/img/select.png b/static/img/select.png new file mode 100644 index 00000000..bcda1db4 Binary files /dev/null and b/static/img/select.png differ diff --git a/static/img/semitransparent-ie8.png b/static/img/semitransparent-ie8.png new file mode 100644 index 00000000..528d21c0 Binary files /dev/null and b/static/img/semitransparent-ie8.png differ diff --git a/static/img/signature.png b/static/img/signature.png new file mode 100644 index 00000000..60c78cb6 Binary files /dev/null and b/static/img/signature.png differ diff --git a/static/img/soc.png b/static/img/soc.png new file mode 100644 index 00000000..59fc664b Binary files /dev/null and b/static/img/soc.png differ diff --git a/static/img/space.png b/static/img/space.png new file mode 100644 index 00000000..ff8d2b18 Binary files /dev/null and b/static/img/space.png differ diff --git a/static/img/spacer.gif b/static/img/spacer.gif new file mode 100644 index 00000000..dd027da0 Binary files /dev/null and b/static/img/spacer.gif differ diff --git a/static/img/sprites.png b/static/img/sprites.png new file mode 100644 index 00000000..805bb799 Binary files /dev/null and b/static/img/sprites.png differ diff --git a/static/img/subjects_list.png b/static/img/subjects_list.png new file mode 100644 index 00000000..023f4afd Binary files /dev/null and b/static/img/subjects_list.png differ diff --git a/static/img/wait.gif b/static/img/wait.gif new file mode 100644 index 00000000..b4d4ff8d Binary files /dev/null and b/static/img/wait.gif differ diff --git a/static/img/wether.png b/static/img/wether.png new file mode 100644 index 00000000..3737c197 Binary files /dev/null and b/static/img/wether.png differ diff --git a/static/img/x2.png b/static/img/x2.png new file mode 100644 index 00000000..22c3c78e Binary files /dev/null and b/static/img/x2.png differ diff --git a/templates/admin/article/blog_form.html b/templates/admin/article/blog_form.html index eb531763..5b221c9f 100644 --- a/templates/admin/article/blog_form.html +++ b/templates/admin/article/blog_form.html @@ -18,7 +18,7 @@ {% block body %}
    {% csrf_token %}
    - {% if article %} Изменить {% else %} Добавить {% endif %}статью + {% if article %} Изменить {% else %} Добавить {% endif %}статью{% if article %}(на сайте){% endif %}
    @@ -88,6 +88,39 @@ {# descriptions #} {% include 'admin/forms/multilang.html' with field='descriptions' form=form languages=languages %}
    + +
    +
    +
    +

    Файлы

    +
    +
    + {% if article %} + {# button that shows modal window with file form #} + Добавить файл + {% else %} +

    Файлы можно добавлять только после введения основных данных

    + {% endif %} + {# this div shows list of files and refreshes when new file added #} +
    + + + + + + + + + + + + + {% include 'file_list.html' with files=files %} + +
    idФайлИмяНазначение
    +
    + +
    @@ -96,4 +129,6 @@
    + +{% include 'admin/includes/file_form.html' with file_form=file_form object=article %} {% endblock %} \ No newline at end of file diff --git a/templates/admin/base.html b/templates/admin/base.html index 87b392d3..743e7d89 100644 --- a/templates/admin/base.html +++ b/templates/admin/base.html @@ -103,6 +103,8 @@
  • Услуги
  • Настройки
  • Главная страница
  • +
  • Мета
  • +
  • Импорт тематик
  • Импорт тегов
  • @@ -112,8 +114,8 @@ + + @@ -162,4 +177,6 @@ +{% 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 07139b34..ff7aaec1 100644 --- a/templates/admin/city/city_add.html +++ b/templates/admin/city/city_add.html @@ -35,6 +35,13 @@ {% with field='name' form=form languages=languages %} {% include 'admin/forms/multilang.html' %} {% endwith %} + {# population #} +
    + +
    + {{ form.inflect }} +
    +
    {# country #}
    diff --git a/templates/admin/conference/conference.html b/templates/admin/conference/conference.html new file mode 100644 index 00000000..0201f346 --- /dev/null +++ b/templates/admin/conference/conference.html @@ -0,0 +1,478 @@ +{% extends 'base.html' %} +{% load static %} +{% load thumbnail %} + +{% block styles %} +.hover{ + display:none; + margin-bottom:10px; + +} +.photo:hover .hover { + display: block; +} +{% endblock %} + +{# Displays exposition form and file form in modal window #} + + {% block scripts %} + + + + {# selects #} + + + {# datepicker #} + + + + + + + + + + {# datetimepicker #} + + + + + {% endblock %} + +{% block body %} +
    {% csrf_token %} +
    + {% if object %} Изменить {% else %} Добавить {% endif %}конференцию{% if object %}(на сайте){% endif %} + +
    +
    +

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

    +
    +
    + {# Hidden inputs uses for comparing with TmpFile objects #} + {{ form.key }} + {# Hidden input uses in clean method for checking url #} + {{ form.exposition_id }} + {# name #} + {% with field='name' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# main_title #} + {% with field='main_title' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# data_begin #} +
    + +
    {{ form.data_begin }} + {{ form.data_begin.errors }} +
    +
    + {# data_end #} +
    + +
    {{ form.data_end }} + {{ form.data_end.errors }} +
    +
    + + {# country #} +
    + +
    {{ form.country }} + {{ form.country.errors }} +
    +
    + {# city #} +
    + +
    {{ form.city }} + {{ form.city.errors }} +
    +
    + {# place #} +
    + +
    {{ form.place }} + {{ form.place.errors }} +
    +
    + {# theme #} +
    + +
    {{ form.theme }} + {{ form.theme.errors }} +
    +
    + {# tag #} +
    + +
    {{ form.tag }} + {{ form.tag.errors }} +
    +
    +
    + {# logo #} +
    + +
    {{ form.logo }} + {{ form.logo.errors }} +
    +
    +
    + +
    +
    +

    Дополнительная информация

    +
    +
    + {# description #} + {% with field='description' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# periodic #} +
    + +
    {{ form.periodic }} + {{ form.periodic.errors }} +
    +
    + {# web_page #} +
    + +
    {{ form.web_page }} + {{ form.web_page.errors }} +
    +
    + {# link #} +
    + +
    {{ form.link }} + {{ form.link.errors }} +
    +
    + {# main_themes #} + {% with field='main_themes' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# time #} + {% with field='time' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# foundation_year #} +
    + +
    {{ form.foundation_year }} + {{ form.foundation_year.errors }} +
    +
    + {# quality_label #} +
    + +
    {{ form.quality_label }} + {{ form.quality_label.errors }} +
    +
    + {# canceled #} +
    + +
    {{ form.canceled }} + {{ form.canceled.errors }} +
    +
    + {# moved #} +
    + +
    {{ form.moved }} + {{ form.moved.errors }} +
    +
    + {# expohit #} +
    + +
    {{ form.expohit }} + {{ form.expohit.errors }} +
    +
    + +
    +
    +
    +
    +

    Условия участия

    +
    +
    + {# currency #} +
    + +
    {{ form.currency }} + {{ form.currency.errors }} +
    +
    + {# tax #} +
    + +
    {{ form.tax }} + {{ form.tax.errors }} +
    +
    + {# min_price #} +
    + +
    {{ form.min_price }} + {{ form.min_price.errors }} +
    +
    + {# max_price #} +
    + +
    {{ form.max_price }} + {{ form.max_price.errors }} +
    +
    + {# discount #} +
    + +
    {{ form.discount }} + {{ form.discount.errors }} +
    +
    + {# discount_description #} + {% with field='discount_description' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + +
    +
    +
    +
    +

    Деловая программа

    +
    +
    + {% if object %} +
    + + + + + + + + + + + + + + + + + + + + + + {% for timetable in timetables %} + + + + + + + + + {% endfor %} + +
    ПрограммаНачалоКонецСпикерыОрганизатор 
    {{ timetable.programe|safe }}{{ timetable.begin|date:"o-m-d H:i" }}{{ timetable.end|date:"o-m-d H:i" }}{{ timetable.speaker }} + {{ timetable.timetable_organiser }} + + +
    +
    + + Добавить program + {% else %} +

    Деловую программу можно добавлять только после введения основных данных

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

    Статистика

    +
    + +
    + {# foundation_year #} +
    + +
    {{ form.foundation_year }} + {{ form.foundation_year.errors }} +
    +
    + {# area #} +
    + +
    {{ form.area }} + {{ form.area.errors }} +
    +
    + {# members #} +
    + +
    {{ form.members }} + {{ form.members.errors }} +
    +
    + {# visitors #} +
    + +
    {{ form.visitors }} + {{ form.visitors.errors }} +
    +
    + + {% if object %} +
    + + + + + + + + + + + + + {% for stat in object.statistic.all %} + + + + + + + + {% endfor %} + +
    ГодПосетителиУчастникиПлощадь
    {{ stat.year }}{{ stat.visitors }}{{ stat.members }}{{ stat.area }} Удалить
    +
    + Добавить год +
    + + + {% else %} + {% endif %} + +
    +
    +
    +

    Файлы

    +
    +
    + {% if object %} + {# button that shows modal window with file form #} + Добавить файл + {% else %} +

    Файлы можно добавлять только после введения основных данных

    + {% endif %} + {# this div shows list of files and refreshes when new file added #} +
    + + + + + + + + + + + + + {% include 'file_list.html' with files=files %} + +
    idФайлИмяНазначение
    +
    + +
    +
    + + {% include 'admin/includes/photogallery.html' with object=object %} + +
    +
    +

    Мета данные

    +
    +
    + {# keywords #} + {% with field='keywords' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# title #} + {% with field='title' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} + {# descriptions #} + {% with field='descriptions' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} +
    +
    + + +
    + + +
    + +
    +
    + + +{% include 'admin/includes/photo_form.html' with form=photo_form object=object %} +{% include 'admin/includes/file_form.html' with file_form=file_form object=object %} +{% include 'admin/includes/stat_form.html' with form=stat_form object=object %} +{% endblock %} \ No newline at end of file diff --git a/templates/admin/conference/conference_all.html b/templates/admin/conference/conference_all.html index 43e458d9..8d0a6bbb 100644 --- a/templates/admin/conference/conference_all.html +++ b/templates/admin/conference/conference_all.html @@ -45,20 +45,16 @@ - + Изменить - - - Копировать - - + - Удалить + Удалить diff --git a/templates/admin/conference/conference_list.html b/templates/admin/conference/conference_list.html index 04a3f2d6..327f4a31 100644 --- a/templates/admin/conference/conference_list.html +++ b/templates/admin/conference/conference_list.html @@ -56,20 +56,14 @@ - + Изменить - - Копировать - - - - - - Удалить + + Удалить @@ -78,7 +72,7 @@ {% endfor %} - Добавить конференцию + Добавить конференцию
    {# pagination #} {% include 'admin/includes/admin_pagination.html' with page_obj=object_list %} diff --git a/templates/admin/exposition/exposition.html b/templates/admin/exposition/exposition.html index 1babf44a..4ef1496b 100644 --- a/templates/admin/exposition/exposition.html +++ b/templates/admin/exposition/exposition.html @@ -78,8 +78,6 @@ {% block body %} -{# Uses multilang.html template for translated fields #} -
    {% csrf_token %}
    {% if object %} Изменить {% else %} Добавить {% endif %}выставку{% if object %}(на сайте){% endif %} @@ -452,7 +450,7 @@ Добавить program {% else %} -

    Деловую программу можна добавлять только после введения основных даных

    +

    Деловую программу можно добавлять только после введения основных данных

    {% endif %} @@ -494,6 +492,39 @@ + {% if object %} +
    + + + + + + + + + + + + + {% for stat in object.statistic.all %} + + + + + + + + {% endfor %} + +
    ГодПосетителиУчастникиПлощадь
    {{ stat.year }}{{ stat.visitors }}{{ stat.members }}{{ stat.area }} Удалить
    +
    + Добавить год + + + + {% else %} + {% endif %} + {% comment %} {% if formset_statistic.errors %}
    {% for form in formset_statistic.forms %} @@ -536,6 +567,7 @@

    Добавить год

    + {% endcomment %}
    @@ -546,7 +578,7 @@ {# button that shows modal window with file form #} Добавить файл {% else %} -

    Файлы можна добавлять только после введения основных даных

    +

    Файлы можно добавлять только после введения основных данных

    {% endif %} {# this div shows list of files and refreshes when new file added #}
    @@ -647,7 +679,7 @@ {% include 'admin/includes/photo_form.html' with form=photo_form object=object %} {% include 'admin/includes/file_form.html' with file_form=file_form object=object %} +{% include 'admin/includes/stat_form.html' with form=stat_form object=object %} {% endblock %} diff --git a/templates/admin/includes/stat_form.html b/templates/admin/includes/stat_form.html new file mode 100644 index 00000000..2dc8f5c9 --- /dev/null +++ b/templates/admin/includes/stat_form.html @@ -0,0 +1,58 @@ + \ No newline at end of file diff --git a/templates/admin/place_exposition/hall.html b/templates/admin/place_exposition/hall.html new file mode 100644 index 00000000..8566f449 --- /dev/null +++ b/templates/admin/place_exposition/hall.html @@ -0,0 +1,59 @@ +{% extends 'base.html' %} +{% load static %} + +{% block scripts %} + + + {# google map не забыть скачать скрипты на локал #} + + + + + {# selects #} + + + + + {# ajax #} + + + + +{% endblock %} + +{% block body %} +
    {% csrf_token %} +
    + Изменить зал +
    +
    +

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

    +
    +
    + {# name #} + {% with field='name' form=form languages=languages %} + {% include 'admin/forms/multilang.html' %} + {% endwith %} +
    + +
    {{ form.number }} + {{ form.number.errors }} +
    +
    + +
    + +
    {{ form.capacity }} + {{ form.capacity.errors }} +
    +
    +
    +
    +
    + + +
    +
    +
    + +{% endblock %} \ No newline at end of file diff --git a/templates/admin/place_exposition/place_exposition.html b/templates/admin/place_exposition/place_exposition.html index 761c9642..e8566217 100644 --- a/templates/admin/place_exposition/place_exposition.html +++ b/templates/admin/place_exposition/place_exposition.html @@ -192,7 +192,7 @@
    -

    Павилионы

    +

    Павильоны

    {% if object %} @@ -200,7 +200,7 @@ - + @@ -212,13 +212,16 @@ - + {% endfor %}
    Название павилионаНазвание павильона Номер Вместимость {{ hall.name }} {{ hall.number }} {{ hall.capacity }} Удалить + Удалить + Изменить +
    {% else %} -

    Павилионы можна добавлять только после введения основных даных

    +

    Павилионы можно добавлять только после введения основных данных

    {% endif %}
    @@ -330,7 +333,7 @@ {# button that shows modal window with file form #} Добавить файл {% else %} -

    Файлы можна добавлять только после введения основных даных

    +

    Файлы можно добавлять только после введения основных данных

    {% endif %} {# this div shows list of files and refreshes when new file added #}
    @@ -358,7 +361,7 @@
    -

    Мета даные

    +

    Мета данные

    diff --git a/templates/admin/service/order_list.html b/templates/admin/service/order_list.html new file mode 100644 index 00000000..e583a22a --- /dev/null +++ b/templates/admin/service/order_list.html @@ -0,0 +1,37 @@ +{% extends 'base.html' %} + +{% block body %} + +
    +
    +

    Список заказов

    +
    +
    + + + + + + + + + + + {% for item in object_list %} + + + + + + + {% endfor %} + +
    idКонтактное лицоТелефонВремя создания
    {{ item.id }}{{ item.person_inf }}{{ item.phone }}{{ item.created }}
    +
    + + {% include 'admin/includes/admin_pagination.html' with page_obj=page_obj %} +
    + {# pagination #} + + +{% endblock %} \ No newline at end of file diff --git a/templates/admin/service/service_add.html b/templates/admin/service/service_add.html index 8b5fa8fa..ce487c45 100644 --- a/templates/admin/service/service_add.html +++ b/templates/admin/service/service_add.html @@ -121,6 +121,45 @@
    +
    +
    +

    Управления услугами

    +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + + + +
    +
    +
    diff --git a/templates/admin/settings/main_page.html b/templates/admin/settings/main_page.html index f66f7933..5018c3f7 100644 --- a/templates/admin/settings/main_page.html +++ b/templates/admin/settings/main_page.html @@ -16,11 +16,13 @@
    {% csrf_token %} {{ event_form.expositions.label }}:    {{event_form.expositions }}     + {% comment %} {{ event_form.conferences.label }}:     {{event_form.conferences }}

    {{ event_form.seminars.label }}:         {{event_form.seminars }}     {{ event_form.webinars.label }}:           {{event_form.webinars }} + {% endcomment %}
    @@ -31,7 +33,7 @@
    -
    +

    Новости

    @@ -43,12 +45,14 @@
    -
    +
    +
    +

    Обзоры

    -
    {% csrf_token %} + {% csrf_token %} {{ article_form }}
    @@ -82,4 +86,51 @@
    +{% endblock %} + +{% block bot_scripts %} + {% endblock %} \ No newline at end of file diff --git a/templates/client/accounts/calendar.html b/templates/client/accounts/calendar.html index 4cb234ab..261d1bfd 100644 --- a/templates/client/accounts/calendar.html +++ b/templates/client/accounts/calendar.html @@ -24,8 +24,35 @@ {% endwith %}
    +
    + {% if events|length > 0 %} +
    +
    {{ days.15|date:"F"}}’{{ days.15|date:"y"}}
    + {% include 'includes/accounts/calendar_list.html' with events=events %} +
    + +
    +
    {% trans 'Все / выделенные:' %}
    + + +
    + {% endif %} + + +
    {% endblock %} {% block scripts %} + {% endblock %} \ No newline at end of file diff --git a/templates/client/accounts/feed.html b/templates/client/accounts/feed.html index 7a895dc2..7b22e691 100644 --- a/templates/client/accounts/feed.html +++ b/templates/client/accounts/feed.html @@ -2,168 +2,165 @@ {% load i18n %} {% load static %} {% block bread_scrumbs %} - + {% endblock %} - - {% block page_title %} -
    -

    {% trans 'Моя лента событий' %}

    -
    +
    +

    {% trans 'Моя лента событий' %}

    +
    {% endblock %} - {% block page_body %} -
    -
    - Фильтрация ленты - - -
    -
    -

    Тематические фильтры не выбраны: (Изменить):

    -
    -
    -
    -
    ~~text~~
    - x +
    +
    + Фильтрация ленты +
    +
    +

    Тематические фильтры не выбраны: (Изменить):

    +
    +
    +
    +
    ~~text~~
    + x +
    + +
    +
    +
    +
    +

    Географические фильтры не выбраны: (Изменить):

    + +
    +
    +
    +
    ~~text~~
    + x +
    + +
    +
    +
    + +
    + {% csrf_token %} +
    +
    +
    +
    + + {% if search_form.th %} + {% include 'client/popups/theme.html' with search_form=search_form filter="filter-" formId="filter-pwSubj" selectedItemTemplate="filter-subj-selected" autoCompleteId="filter-subj-complete-block" filterInputId="filter-subj-fliter-input" selectedItemsContainer="filter-csb-subj-selected-items" subjectTriggerWrapId="filter-subj-checks" exhibitionCheck="filter-exhibition-check" conferenceCheck="filter-conference-check" prefix="f-s-" submitText="Применить" %} + {% endif %} + + {% if search_form.area %} + {% include 'client/popups/place.html' with search_form=search_form filter="filter-" formId="filter-pwPlace" selectedItemTemplate="filter-csb-selected" autoCompleteId="filter-place-complete-block" filterInputId="filter-place-filter-input" selectedItemsContainer="filter-csb-selected-items" prefix="f-p-" submitText="Применить" %} + {% endif %} + +
    +
    - -
    -
    -
    -
    -

    Географические фильтры не выбраны: (Изменить):

    - -
    -
    -
    -
    ~~text~~
    - x -
    - -
    -
    -
    - - -
    - {% csrf_token %} -
    -
    -
    -
    - - {% if search_form.th %} - {% include 'client/popups/theme.html' with search_form=search_form filter="filter-" formId="filter-pwSubj" selectedItemTemplate="filter-subj-selected" autoCompleteId="filter-subj-complete-block" filterInputId="filter-subj-fliter-input" selectedItemsContainer="filter-csb-subj-selected-items" subjectTriggerWrapId="filter-subj-checks" exhibitionCheck="filter-exhibition-check" conferenceCheck="filter-conference-check" prefix="f-s-" %} - {% endif %} - - {% if search_form.area %} - {% include 'client/popups/place.html' with search_form=search_form filter="filter-" formId="filter-pwPlace" selectedItemTemplate="filter-csb-selected" autoCompleteId="filter-place-complete-block" filterInputId="filter-place-filter-input" selectedItemsContainer="filter-csb-selected-items" prefix="f-p-" %} - {% endif %} -
    -
    -
    - -
    - - -
    - {% block scripts %} - - - - - {% endblock %} -
    - - {% include 'includes/exposition/exposition_list.html' with object_list=object_list %} - - {% include 'includes/catalog_paginator.html' with page_obj=page_obj %} + +
    +
    +

    *{% trans ' Вы можете настроить ленту событий, один раз выбрав интересные темы и географию с помощью кнопки «Фильтрация ленты».' %}

    +
    + {% if object_list %} + {% include 'includes/exposition/exposition_list.html' with object_list=object_list %} + {% else %} +

    + + + + + {% trans "Увы, событий, соответствующих выбранным фильтрам, нет в каталоге.
    Попробуйте укрупнить параметры поиска" %} +
    +

    + {% endif %} + {% include 'includes/catalog_paginator.html' with page_obj=page_obj %} + {% if request.GET.debug == '1' %} + + {% else %} + + {% endif %} + +
    {% endblock %} - diff --git a/templates/client/accounts/fill_company.html b/templates/client/accounts/fill_company.html index 7266a0e2..c338e95d 100644 --- a/templates/client/accounts/fill_company.html +++ b/templates/client/accounts/fill_company.html @@ -2,606 +2,478 @@ {% load static %} {% load i18n %} {% load template_filters %} - {% block style %} - - + + {% endblock %} - {% block bread_scrumbs %} {% endblock %} - {% block page_title %} {% endblock %} - {% block content_list %}
    -
    - - - -
    -
    - - - -
    - {{ name_form.name.value }} - -
    - редактировать -
    -
    {% csrf_token %} - -
    - -
    - -
    - {{ name_form.name }} -
    -
    - -
    - -
    - -
    -
    - - закрыть -
    -
    -
    -
    - - -
    - {% endblock %} - - {% block pre_scripts %} - - + + {% endblock %} - {% block scripts %} - - - - - +{% else %} + +{% endif %} - - - - - - - {% endblock %} +
    + +
    + {{ web_page_form.web_page }} +
    +
    +
    +
    + +
    + + {% trans 'закрыть' %} +
    +
    +
    +
    +
    +
    +
    + {% if about_form.about.value %} +
    {% trans 'О себе:' %}
    + {% endif %} + + +
    + + + {% block scripts %} + + + + {% if request.GET.debug == '1' %} + + {% else %} + + {% endif %} + + {% endblock %} {% endblock %} {% block popup %} {% if company_form %} - {% include 'popups/create_company.html' with form=company_form %} + {% include 'popups/create_company.html' with form=company_form %} {% endif %} {% endblock %} {% block pre_scripts %} - - + + {% endblock %} diff --git a/templates/client/accounts/profile.html b/templates/client/accounts/profile.html index ecf4ac37..ea432419 100644 --- a/templates/client/accounts/profile.html +++ b/templates/client/accounts/profile.html @@ -2,310 +2,262 @@ {% load static %} {% load i18n %} {% load template_filters %} - - {% block bread_scrumbs %} {% endblock %} - {% block page_title %} -
    -

    {% trans 'Личный кабинет' %}

    -
    +
    +

    {% trans 'Личный кабинет' %}

    +
    {% endblock %} - {% block content_list %}
    -
    - - {# avatar #} - - {# END avatar #} -
    -
    - {# country and city #} -
    - {% if home_form.instance.country %} - - {% else %} - - {% endif %} - {{ home_form.instance.country }} - - - {% if home_form.instance.city %} - - {% else %} - - {% endif %} - , {{ home_form.instance.city }} - - -
    - {% trans 'редактировать' %} -
    -
    {% csrf_token %} -
    - -
    - -
    - {{ home_form.country }} - -
    -
    - -
    - -
    - -
    -
    - -
    - + {% trans 'закрыть' %} +
    +
    +
    + + {# END avatar #} +
    +
    + {# country and city #} +
    + {% if home_form.instance.country %} + + {% else %} + + {% endif %} + {{ home_form.instance.country }} + + {% if home_form.instance.city %} + + {% else %} + + {% endif %} + , {{ home_form.instance.city }} + +
    + {% trans 'редактировать' %} +
    + {% csrf_token %} +
    +
    + +
    + {{ home_form.country }} +
    +
    +
    + +
    + +
    +
    +
    - - {% trans 'закрыть' %} -
    -
    -
    - {# END country and city #} - - {# name #} -
    - {{ name_form.get_full_name }} - +
    +
    + {# END country and city #} + {# name #} +
    + {{ name_form.get_full_name }} +
    {% trans 'редактировать' %}
    {% csrf_token %} - + method="post" method="post">{% csrf_token %}
    -
    - {{ name_form.first_name }} + {{ name_form.first_name }} +
    +
    +
    + +
    + {{ name_form.last_name }}
    -
    - -
    - {{ name_form.last_name }} -
    -
    -
    -
    - {% trans 'закрыть' %}
    -
    - {# END name #} -
    - - {# position #} -
    -

    - {{ work_form.position.value }} - {% if work_form.work.value %} - {% trans 'в' %} {{ work_form.work.value }} - {% endif %} -

    - - + {# END name #} + + {# position #} +
    +

    + {{ work_form.position.value }} + {% if work_form.work.value %} + {% trans 'в' %} {{ work_form.work.value }} + {% endif %} +

    +
    + {% trans 'редактировать' %}
    {% csrf_token %} -
    - -
    - +
    +
    {{ work_form.position }}
    -
    -
    - {{ work_form.work }} -
    +
    + {{ work_form.work }} +
    -
    -
    - {% trans 'закрыть' %} -
    -
    -
    - {# END position #} - - - {# description #} -
    -

    {{ about_company_form.about_company.value }}

    - +
    +
    + {# END position #} + {# description #} +
    +

    {{ about_company_form.about_company.value }}

    +
    + {% trans 'редактировать' %}
    {% csrf_token %} -
    -
    - {{ about_company_form.about_company }} + {{ about_company_form.about_company }}
    -
    -
    - {% trans 'закрыть' %}
    -
    -
    - {# END description #} -
    - -
    - + {# END description #} +
    +
    +
    + {% trans 'редактировать профиль' %} + {% trans 'завершить редактирование' %} +
    + -
    +
    {% trans 'редактировать' %}
    {% csrf_token %} -
    -
    {{ social_form.facebook }}
    -
    -
    - {{ social_form.linkedin }} -
    +
    + {{ social_form.linkedin }} +
    -
    - +
    - {{ social_form.vk }} + {{ social_form.vk }}
    -
    {{ social_form.twitter }}
    -
    -
    - {% trans 'закрыть' %}
    -
    -
    - {# contacts #} - -
    - -
    - {# about #} -
    -
    {% trans 'О себе:' %}
    - -
    -

    {{ about_form.about.value }}

    - -
    - {% trans 'редактировать' %} -
    -
    {% csrf_token %} - -
    - -
    - -
    - {{ about_form.about }} -
    -
    - -
    - -
    - -
    -
    - - {% trans 'закрыть' %} -
    -
    -
    -
    - {# END about #} - -
    -
    +
    +
    + {% if web_page_form.web_page.value %} + + {% if web_page_form.web_page.value %} + {{ web_page_form.web_page.value }} + {% endif %} + + {% endif %} +
    + {% trans 'редактировать' %} +
    +
    {% csrf_token %} +
    +
    + +
    + {{ web_page_form.web_page }} +
    +
    +
    +
    + +
    +
    + {% trans 'закрыть' %} +
    +
    +
    + {# END contacts #} +
    +
    +
    + {# about #} +
    +
    {% trans 'О себе:' %}
    +
    +

    {{ about_form.about.value }}

    +
    + {% trans 'редактировать' %} +
    +
    {% csrf_token %} +
    +
    + +
    + {{ about_form.about }} +
    +
    +
    +
    + +
    +
    + {% trans 'закрыть' %} +
    +
    +
    +
    + {# END about #} +
    + {% endblock %} {% block scripts %} +{% if request.GET.debug == '1' %} +{% else %} + +{% endif %} +{% else %} + +{% endif %} + +{% endblock %} +{% block paginator %} + {% include 'includes/catalog_paginator.html' with page_obj=page_obj %} {% endblock %} \ No newline at end of file diff --git a/templates/client/article/catalog.html b/templates/client/article/catalog.html new file mode 100644 index 00000000..46a79584 --- /dev/null +++ b/templates/client/article/catalog.html @@ -0,0 +1,47 @@ +{% extends 'base_catalog.html' %} +{% load template_filters %} +{% load i18n %} + + + +{% block bread_scrumbs %} + +{% endblock %} + + +{% block page_title %} +
    +

    {% if meta %}{{ meta.h1 }}{% else %}{% trans 'Новости' %}: {{ filter_object.name }}{% endif %}

    +
    + + {% ifequal catalog_url '/news/tag/' %} + {% include 'includes/article/catalog_filter_period.html' %} + {% endifequal %} +{% endblock %} + +{% block content_list %} + {% ifequal catalog_url '/news/tag/' %} + {% include 'client/includes/article/news_list.html' with object_list=object_list %} + {% else %} + {% include 'client/includes/article/blog_list.html' with object_list=object_list %} + {% endifequal %} +{% endblock %} diff --git a/templates/client/article/news.html b/templates/client/article/news.html index 98d8f78d..561fc14c 100644 --- a/templates/client/article/news.html +++ b/templates/client/article/news.html @@ -17,39 +17,40 @@
    - {% include 'includes/show_logo.html' with obj=object %} + + {% include 'includes/article/article_logo.html' with obj=object %}

    {{ object.main_title }}

    - {{ object.publish_date }}{{ object.get_event.name }} -

    Смартфоны, планшеты, программные решения и аксессуары заполнили каждый свободный метр экспоцентра Барселоны в надежде стать лидером продаж в своем сегменте. За день до официального старта восьмой выставки-конгресса Mobile World Congress глава GSMA Джон Хоффман торжественно отметил новую точку отсчета в богатой истории мероприятия: два монумента, которые появились у входа в экспоцентр, кажется, навсегда закрепили за Барселоной статус столицы мобильной индустрии.

    + {{ object.created|date:"d E Y" }}{% if object.get_event %}{{ object.get_event.name }}{% endif %}
    - {{ object.description }} + {{ object.description|safe }}
    - Источник: {{ object.author }} - {% include 'includes/article_tags.html' with obj=object %} + {% trans 'Источник' %}: {{ object.author }} + {% if object.tag.all.exists %} + {% include 'client/includes/article_tags.html' with obj=object %} + {% endif %}
    -
    - -
    -
    -
    - +
    {% for news in object.similar %}
    - -

    Самое интересное на Baby Active' 2014

    -

    С 16 по 18 мая в Выставочном центре «АККО Интернешнл», на территории парка им. А.С. Пушкина, состоится Выставка- -фестиваль семейного досуга Baby Active' 2014 («Активный ребенок»).

    - 28 апреля 2014РИФ-2014 + + + {% include 'includes/show_logo.html' with obj=news %} + + +

    {{ news.main_title }}

    +

    {{ news.preview }}

    + {{ news.publish_date|date:"d E Y" }}{% if news.get_event %}{{ news.get_event.name }}<{% endif %}
    +
    {% endfor %}
    diff --git a/templates/client/article/news_list.html b/templates/client/article/news_list.html index eb38670b..9e671309 100644 --- a/templates/client/article/news_list.html +++ b/templates/client/article/news_list.html @@ -1,112 +1,58 @@ {% extends 'base_catalog.html' %} +{% load static %} {% load i18n %} {% load template_filters %} - {% block bread_scrumbs %} - {% endblock %} - {% block page_title %} -
    -

    {% trans 'Новости' %}:

    -
    +
    +

    {% trans 'Новости' %}:

    +
    {% endblock %} - {% block content_list %} -
    - -
    -
    - -
    -
    - -
    -
    -
    -
    -
    -
      -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    -
    -
    -
    - -
    -
    - -
    - -
    -
    -
    -
    -
    -
      -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    • -
    -
    -
    -
    - -
    -
    -
    - -
    -
    -
    -
    -
    - {% for news in object_list %} - - {% endfor %} -
    +
    +
    +
    +
    +
    + +
    + + {{ article_filter_form.theme }} +
    +
    +
    + +
    + {{ article_filter_form.tag }} +
    +
    +
    +
    +
    +{% include 'client/includes/article/news_list.html' with object_list=object_list %} +{% if request.GET.debug == '1' %} + +{% else %} + +{% endif %} + +{% endblock %} +{% block paginator %} + {% include 'client/includes/catalog_paginator.html' with page_obj=page_obj %} {% endblock %} diff --git a/templates/client/base_catalog.html b/templates/client/base_catalog.html index 7b85c67e..7ae7dab6 100644 --- a/templates/client/base_catalog.html +++ b/templates/client/base_catalog.html @@ -19,11 +19,15 @@ {% include 'client/includes/online_consult.html' %} {% block aside_banner1 %} -
    -
    - + {% if theme_for_filter.id == 27 or theme_for_filter.id == 9 or theme_for_filter.id == 48 %} +
    +
    + + + +
    -
    + {% endif %} {% endblock %} {% include 'client/includes/services.html' %} @@ -32,14 +36,25 @@ {% include 'client/includes/announces.html' %} {% block asside_banner2 %} -
    -
    - + + + {% comment %} +
    +
    + + + +
    -
    - {% endblock %} + {% endcomment %} + - {% include 'client/includes/news.html' %} + {% endblock %} + {% include 'client/includes/side_confs.html' %} +
    +
    + {% include 'client/includes/news.html' with news=news_list %} +
    {% block aside_vk %}
    @@ -52,6 +67,11 @@ {% with search_form=search_form %} {% include 'client/includes/catalog_search.html' %} {% endwith %} + {% block under_search_baner %} +
    + +
    + {% endblock %} {% block bread_scrumbs %} {% with filter=filter %} diff --git a/templates/client/blank.html b/templates/client/blank.html index 3e786ee1..2755ecc6 100644 --- a/templates/client/blank.html +++ b/templates/client/blank.html @@ -1,136 +1,188 @@ {% load static %} {% load i18n %} {% 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, register, login, search popups blocks for add or change: title(title), styles(style), header(header), footer(footer) banners(header_banner), - scripts(script), popups(popup) and blocks: main_part, top, search, catalog, announces, partners, services + scripts(script), popups(popup) and blocks: main_part, top, search, catalog, announces, partners, services head with title block, style block {% endcomment %} - - + + + - {% include 'includes/meta.html' %} - + {% include 'includes/meta.html' %} + - - - - - - + {% if request.GET.debug == '1' %} + + {% else %} + + {% endif %} + + + {% if request.GET.debug == '1' %} + + {% else %} + + {% endif %} + + {% block styles %} + {% endblock %} + - - - - - + + {% if request.GET.debug == '1' %} + + {% else %} + + {% endif %} + + + + + + + -

    You are using an outdated browser. Please upgrade your browser or activate Google Chrome Frame to improve your experience.

    ---> -
    - {% block header %} - {% include 'header.html' %} - {% endblock %} - {% block main_part %} - {% endblock %} - - {% block top %} - {% endblock %} - - {% block search %} - {% endblock %} - - {% block catalog %} - {% endblock %} - - {% block announces %} - {% endblock %} - - {% block partners %} - {% endblock %} - - {% block services %} - {% endblock %} - - {% block footer %} - {% include 'footer.html' %} - {% endblock %} -
    -
    - {% if not user.is_authenticated %} - {% include 'client/popups/login.html' %} - {% include 'client/popups/register.html' %} - {% include 'client/popups/reg_send.html' %} - - {% endif %} - - - {% comment "Убрал т.к. функционал диалоговых окон расширенного поиска переносится в catalog_search.html" %} - {% include 'client/popups/theme.html' %} - {% if search_form.area %} - {% include 'client/popups/place.html' with search_form=search_form search_action=search_action %} - {% endif %} - {% if search_form.fr %} - {% with search_form=search_form search_action=search_action type=type%} - {% include 'client/popups/period.html' %} - {% endwith %} +{% endcomment %} +
    + {% block header %} + {% include 'client/includes/header.html' %} + {% endblock %} + {% block main_part %} + {% endblock %} + + {% block top %} + {% endblock %} + + {% block search %} + {% endblock %} + + {% block catalog %} + {% endblock %} + + {% block announces %} + {% endblock %} + + {% block partners %} + {% endblock %} + + {% block services %} + {% endblock %} + + {% block footer %} + {% include 'client/includes/footer.html' %} + {% endblock %} +
    +
    + {% if not user.is_authenticated %} + {% include 'client/popups/login.html' %} + {% include 'client/popups/register.html' %} + {% include 'client/popups/reg_send.html' %} + + {% endif %} + + {% include 'client/popups/callback.html' %} + + {# if user doesnt have url- show form #} + + {% if not request.user.is_anonymous %} + {% if not request.user.url %} + {% include 'client/popups/user_information.html' with form=reg_complete %} + {% if request.GET.debug == '1' %} + + {% else %} + + {% endif %} {% endif %} - {% endcomment %} - {% include 'client/popups/callback.html' %} - - {# if user doesnt have url- show form #} + {% endif %} - {% if not request.user.is_anonymous %} - {% if not request.user.url %} - {% include 'client/popups/user_information.html' with form=reg_complete %} - {% endif %} - {% endif %} - - {% block popup %} - {% endblock %} -
    + {% block popup %} + {% endblock %} +
    {% block photogallery %} - {% endblock %} - - - - - - +{# js libs #} + +{% if request.GET.debug == '1' %} + +{% else %} + +{% endif %} - diff --git a/templates/client/company/companies_list.html b/templates/client/company/companies_list.html index 4a2eebbe..944db5fc 100644 --- a/templates/client/company/companies_list.html +++ b/templates/client/company/companies_list.html @@ -17,7 +17,7 @@ {% endblock %} {% block content_list %} - {% include 'includes/company/company_list.html' with object_list=object_list %} + {% include 'client/includes/company/company_list.html' with object_list=object_list %} {% endblock %} {% block paginator %} diff --git a/templates/client/company/company_detail.html b/templates/client/company/company_detail.html index b13977b2..934b7b7d 100644 --- a/templates/client/company/company_detail.html +++ b/templates/client/company/company_detail.html @@ -13,11 +13,10 @@ {% endblock %} {% block content_list %} - {% if request.user == object.creator %} - - {% include 'client/includes/company/company_edit.html' %} - {% else %} + {% if request.user != object.creator or request.GET.logout %} {% include 'client/includes/company/company_object.html' with company=object %} + {% else %} + {% include 'client/includes/company/company_edit.html' with company=object %} {% endif %} diff --git a/templates/client/exposition.html b/templates/client/exposition.html index 01d63f80..c5d45b9c 100644 --- a/templates/client/exposition.html +++ b/templates/client/exposition.html @@ -122,12 +122,12 @@
  • 2. {% trans 'Забронируйте отель по лучшей цене' %}
    - booking.com + booking.com
  • 3. {% trans 'Купите авиабилеты по лучшему тарифу' %}
    - AnywayAnyday + aviasales.ru.ru
  • @@ -191,6 +191,7 @@
    + {% if exposition.company.all %}
    @@ -310,6 +311,7 @@
    + {% endfor %}
    diff --git a/templates/client/exposition/catalog.html b/templates/client/exposition/catalog.html index 74117eb3..cb8941dc 100644 --- a/templates/client/exposition/catalog.html +++ b/templates/client/exposition/catalog.html @@ -24,7 +24,8 @@ {% block page_title %}
    -

    {% trans 'Выставки' %}: {{ filter_object.name }}

    + {#

    {% trans 'Выставки' %}: {{ filter_object.name }}

    #} +

    {% if meta %}{{ meta.h1 }}{% else %}{% trans 'Выставки' %}: {{ filter_object.name }}{% endif %}

    {% include 'includes/exposition/catalog_filter_period.html' %} diff --git a/templates/client/exposition/catalog_theme.html b/templates/client/exposition/catalog_theme.html new file mode 100644 index 00000000..ab39aceb --- /dev/null +++ b/templates/client/exposition/catalog_theme.html @@ -0,0 +1,66 @@ +{% extends 'base_catalog.html' %} +{% load template_filters %} +{% load i18n %} + +{% block bread_scrumbs %} + +{% endblock %} + + +{% block page_title %} +
    + {#

    {% trans 'Выставки' %}: {{ filter_object.name }}

    #} +

    {% if meta %}{{ meta.h1 }}{% else %}{% trans 'Выставки' %}: {{ filter_object.name }}{% endif %}

    +
    + + {% include 'includes/exposition/catalog_filter_period.html' %} + +{% endblock %} + +{% block content_list %} + {% include 'includes/exposition/exposition_list.html' with object_list=object_list %} +{% endblock %} + +{% block paginator %} + {% include 'includes/catalog_paginator.html' with page_obj=page_obj %} +{% endblock %} \ No newline at end of file diff --git a/templates/client/exposition/exposition_by.html b/templates/client/exposition/exposition_by.html index 00a24203..8741f18d 100644 --- a/templates/client/exposition/exposition_by.html +++ b/templates/client/exposition/exposition_by.html @@ -23,20 +23,22 @@ {% endblock %} {% block content_list %} - {% for obj in object_list %} - {% 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.expositions_number }}) -
    • - {% set prev_word = obj.name %} - {% endfor %} + {% 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.expo_count }}) +
    • + {% set prev_word = obj.name %} + {% endfor %} + {% endwith %} {% endblock %} diff --git a/templates/client/exposition/exposition_list.html b/templates/client/exposition/exposition_list.html index 75b744b7..8fc3bfd1 100644 --- a/templates/client/exposition/exposition_list.html +++ b/templates/client/exposition/exposition_list.html @@ -23,7 +23,7 @@ {% block page_title %}
      -

      {% trans 'Выставки' %}

      +

      {% if meta %}{{ meta.h1 }}{% else %}{% trans 'Выставки' %}{% endif %}

      {% include 'includes/exposition/catalog_filter_period.html' %} diff --git a/templates/client/exposition/exposition_price.html b/templates/client/exposition/exposition_price.html index cd56c0a6..3944e886 100644 --- a/templates/client/exposition/exposition_price.html +++ b/templates/client/exposition/exposition_price.html @@ -6,215 +6,214 @@ {% block content_list %} - {% block content_text %} - {% block page_body %} -
      -
      - - -
      -
      -
      - {% if object_list.0.main_title %} - {{ object_list.0.main_title|safe }} - {% else %} - {{ object_list.0.name|safe }} - {% endif %} -
      -
      - -
      - {% with obj=object_list.0 %} - {% include 'client/includes/show_date_block.html' %} - {% endwith %} -
      - {% if object_list.0.place %} -
      -
      -
      - {{ object_list.0.place.address.address }} -
      - -
      - - -
      - {% endif %} - - -
      -
      -
      -
      {% trans 'Стоимость посещения и участия' %}
      -
      - -
      -
      - -
      -
      {% trans 'Для посещения' %}
      - -
      {% trans 'Стоимость билетов' %}
      - -
      - -
        - {% if object_list.0.price_day %} -
      • -
        {{ object_list.0.price_day }} €
        -
        {% trans 'на 1 день' %}
        -
      • - {% endif %} - {% if object_list.0.price_all %} -
      • -
        {{ object_list.0.price_all }} €
        -
        {% trans 'на все дни' %}
        -
      • - {% endif %} - -
      - -
      {% trans 'Предварительная регистрация' %}
      - -
      - -
      - -
        - {% if object_list.0.price_day_bar %} -
      • -
        {{ object_list.0.price_day_bar }} €
        - -
        на 1 день
        -
      • - {% endif %} - {% if object_list.0.price_all_bar %} -
      • -
        {{ object_list.0.price_all_bar }} €
        -
        {% trans 'на все дни' %}
        -
      • - {% endif %} - -
      - -
      {% trans 'Регистрация на' %} {% trans 'стойке' %}
      - -
      - -
      - -
      -
      {% trans 'Выставка открыта для' %}:
      -
        - {{ object_list.0.get_audience }} - -
      -
      -
      +{% block content_text %} +{% block page_body %} +
      +
      +
      +
      + {% if object_list.0.discount %} + {% trans 'Скидка' %} -{{ object_list.0.discount }}% + +
      {{ object_list.0.discount_description|safe }}
      + {% endif %} +
      + + +
      +
      +
      + {% if object_list.0.main_title %} + {{ object_list.0.main_title|safe }} + {% else %} + {{ object_list.0.name|safe }} + {% endif %} +
      +
      + +
      + {% with obj=object_list.0 %} + {% include 'client/includes/show_date_block.html' %} + {% endwith %} +
      + {% if object_list.0.place %} +
      +
      +
      + {{ object_list.0.place.address.address }} +
      + +
      + + +
      + {% endif %} + + +
      +
      +
      +
      {% trans 'Стоимость посещения и участия' %}
      +
      + +
      +
      + +
      +
      {% trans 'Для посещения' %}
      -
      -
      {% trans 'Для участия' %}
      +
      {% trans 'Стоимость билетов' %}
      -
      {% trans 'Стоимость аренды 1м²' %}
      +
        - {% if object_list.0.max_closed_equipped_area %} -
      • - -
        {{ object_list.0.max_closed_equipped_area }} €
        -
        {% trans 'оборудованная площадь' %}
        -
      • - {% endif %} - - {% if object_list.0.max_closed_area %} -
      • -
        {{ object_list.0.max_closed_area }} €
        -
        {% trans 'необорудованная площадь' %}
        -
      • - {% endif %} - - {% if object_list.0.max_open_area %} -
      • -
        {{ object_list.0.max_open_area }} €
        -
        {% trans 'открытая площадь' %}
        -
      • - {% endif %} + {% if object_list.0.price_day %} +
      • +
        {{ object_list.0.price_day }} €
        +
        {% trans 'на 1 день' %}
        +
      • + {% endif %} + {% if object_list.0.price_all %} +
      • +
        {{ object_list.0.price_all }} €
        +
        {% trans 'на все дни' %}
        +
      • + {% endif %}
      - {% trans 'Заявка на участие' %} +
      {% trans 'Предварительная регистрация' %}
      -
      - {% if object_list.0.min_stand_size %} -

      {% trans 'Минимальный размер стенда' %} — {{ object_list.0.min_stand_size }}м²

      - {% endif %} - {% if object_list.0.registration_payment %} -

      {% trans 'Регистрационный взнос' %} — {{ object_list.0.registration_payment }}€

      - {% endif %} - {% if object_list.0.application_deadline %} -

      {% trans 'Крайний срок подачи заявки' %} — {{ object_list.0.application_deadline }}

      - {% endif %} +
      + +
      + +
        + {% if object_list.0.price_day_bar %} +
      • +
        {{ object_list.0.price_day_bar }} €
        + +
        на 1 день
        +
      • + {% endif %} + {% if object_list.0.price_all_bar %} +
      • +
        {{ object_list.0.price_all_bar }} €
        +
        {% trans 'на все дни' %}
        +
      • + {% endif %} + +
      + +
      {% trans 'Регистрация на' %} {% trans 'стойке' %}
      -
      +
      +
      + +
      +
      {% trans 'Выставка открыта для' %}:
      +
        + {{ object_list.0.get_audience }} + +
      +
      +
      -
      +
      +
      {% trans 'Для участия' %}
      + +
      {% trans 'Стоимость аренды 1м²' %}
      + +
        + {% if object_list.0.max_closed_equipped_area %} +
      • + +
        {{ object_list.0.max_closed_equipped_area }} €
        +
        {% trans 'оборудованная площадь' %}
        +
      • + {% endif %} + + {% if object_list.0.max_closed_area %} +
      • +
        {{ object_list.0.max_closed_area }} €
        +
        {% trans 'необорудованная площадь' %}
        +
      • + {% endif %} + + {% if object_list.0.max_open_area %} +
      • +
        {{ object_list.0.max_open_area }} €
        +
        {% trans 'открытая площадь' %}
        +
      • + {% endif %} + +
      + + {% trans 'Заявка на участие' %} + +
      + {% if object_list.0.min_stand_size %} +

      {% trans 'Минимальный размер стенда' %} — {{ object_list.0.min_stand_size }}м²

      + {% endif %} + {% if object_list.0.registration_payment %} +

      {% trans 'Регистрационный взнос' %} — {{ object_list.0.registration_payment }}€

      + {% endif %} + {% if object_list.0.application_deadline %} +

      {% trans 'Крайний срок подачи заявки' %} — {{ object_list.0.application_deadline }}

      + {% endif %} + +
      + +
      +
      -
      -
      -
      -
      - -
      - {% endblock %} - {% endblock %} +
      + + +
      + +
      +{% endblock %} +{% endblock %} {% endblock %} diff --git a/templates/client/exposition/search.html b/templates/client/exposition/search.html index a0409a88..6aa7d985 100644 --- a/templates/client/exposition/search.html +++ b/templates/client/exposition/search.html @@ -17,7 +17,18 @@ {% block content_list %} {% with query=object_list %} - {% include 'includes/exposition/search_result.html' %} + {% if query %} + {% include 'client/includes/exposition/search_result.html' %} + {% else %} +

      + + + + + {% trans "Увы, событий, соответствующих выбранным фильтрам, нет в каталоге.
      Попробуйте укрупнить параметры поиска" %} +
      +

      + {% endif %} {% endwith %} {% endblock %} diff --git a/templates/client/exposition/statistic.html b/templates/client/exposition/statistic.html index 6d850642..ba03edd0 100644 --- a/templates/client/exposition/statistic.html +++ b/templates/client/exposition/statistic.html @@ -1,4 +1,5 @@ {% extends 'base_catalog.html' %} +{% load static %} {% load template_filters %} {% load i18n %} @@ -19,8 +20,39 @@ {% block content_list %} {% include 'client/includes/exposition/statistic.html' with exposition=object %} + + {% endblock %} {% block paginator %} -{% endblock %} \ No newline at end of file +{% endblock %} + diff --git a/templates/client/exposition/visitors.html b/templates/client/exposition/visitors.html index 84cfe71b..6762df72 100644 --- a/templates/client/exposition/visitors.html +++ b/templates/client/exposition/visitors.html @@ -17,7 +17,7 @@ {% endblock %} {% block content_list %} - {% include 'includes/exposition/visitors.html' with object_list=object_list %} + {% include 'client/includes/exposition/visitors.html' with object_list=object_list %} {% endblock %} {% block paginator %} diff --git a/templates/client/gulpfile.js b/templates/client/gulpfile.js index 419ee0e5..e3b6b790 100644 --- a/templates/client/gulpfile.js +++ b/templates/client/gulpfile.js @@ -15,7 +15,7 @@ gulp.task('make-vendor-js', function () { 'static_client/js/jquery.mousewheel.min.js', 'static_client/js/idangerous.swiper-2.4.min.js', 'static_client/js/jquery.mCustomScrollbar.concat.min.js', - 'static_client/js/jquery.fancybox.pack.js', + 'static_client/lib/fancybox/jquery.fancybox.js', 'static_client/js/jquery.placeholder.js', 'static_client/js/jquery.phototag.js', 'static_client/js/dna.min.js', @@ -37,7 +37,7 @@ gulp.task('make-vendor-css', function () { 'static_client/css/jquery.mCustomScrollbar.min.css', 'static_client/css/jquery-ui-1.10.3.custom.css', 'static_client/css/jquery.mousewheel.min.js', - 'static_client/css/jquery.fancybox.css', + 'static_client/lib/fancybox/jquery.fancybox.css', 'static_client/css/phototag.css', 'static_client/css/regions.css', 'static_client/css/select2.css' @@ -51,7 +51,7 @@ gulp.task('make-vendor-css', function () { }); gulp.task('main-css', function () { gulp.src('static_client/css/main.css') - .pipe(newer('static_client/css/')) + .pipe(newer('static_client/css_min/')) .pipe(autoprefixer({ browsers:['> 1%', 'Opera > 11', 'Explorer >= 8', 'Firefox >20', 'Chrome > 20'] })) diff --git a/templates/client/includes/accounts/calendar_list.html b/templates/client/includes/accounts/calendar_list.html new file mode 100644 index 00000000..f27fa55c --- /dev/null +++ b/templates/client/includes/accounts/calendar_list.html @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/templates/client/includes/accounts/calendar_table.html b/templates/client/includes/accounts/calendar_table.html index fab0687d..d7ed91fa 100644 --- a/templates/client/includes/accounts/calendar_table.html +++ b/templates/client/includes/accounts/calendar_table.html @@ -1,187 +1,182 @@ {% load static %} {% load i18n %} {% load template_filters %} - - -
      - -
      -
      -
      - < -
      {{ days.0|date:"F"}}’{{ days.0|date:"y"}}
      - > -
      -
      -
      -
      -
      - {% with events=events %} - - - - {% for day in days %} - {% ifnotequal day current_day %} - - {% else %} - - {% endifnotequal %} - {% endfor %} - - - - - {# первый ряд с отображениями дней где нет событий #} - - {% for day in days %} - - {% if day_colspan|get_item:day|get_item:'event' %} - {% ifnotequal day current_day %} - - {% else %} - - {% endifnotequal %} - - {% else %} - {% if day_colspan|get_item:day|get_item:'counter' %} - {# здесь ячейка с днями без событий #} - - - {% endif %} - - {% endif %} - - - {% endfor %} - - - {% for day in days %} - {% ifnotequal day current_day %} - - {% else %} - - {% endifnotequal %} - {% endfor %} - - - - {% for event in events %} - - {% for day in days %} - - {% if event|in_event:day %} - {% if day.month == event.data_begin.month %} - {% if day.day == event.data_begin.day %} - - {% endif %} - {% else %} - {% if day.day == event.data_end.day %} - - {% endif %} - {% endif %} - {% else %} - {% ifnotequal day current_day %} - - {% else %} - - {% endifnotequal %} - - {% endif %} - {% endfor %} - - - - {% for day in days %} - {% ifnotequal day current_day %} - - {% else %} - - {% endifnotequal %} - {% endfor %} - - - - {% endfor %} - - -
      {{ day|date:"d" }}/{% if LANGUAGE_CODE == 'ru' %}{{ day|get_rus_day }}{% else %}{{ day|date:"D" }}{% endif %}
      -
      -
      {% trans 'Сегодня' %}
      - {{ day|date:"d" }}/{% if LANGUAGE_CODE == 'ru' %}{{ day|get_rus_day }}{% else %}{{ day|date:"D" }}{% endif %} -
      -
      -
      -
      {% trans "Нет отмеченых событий" %}
      -
      -
      -
      -
      -

      {{ event.name|safe }}

      - -
      -
      - - -
      -
      {{ event.country }}, {{ event.city }} - {% if event.plave %} - , {{ event.place.address.address }} - {% endif %} -
      -
      -
      -
      -
      -
      -
      -

      {{ event.name|safe }}

      - -
      -
      - - -
      -
      {{ event.country }}, {{ event.city }} - {% if event.plave %} - , {{ event.place.address.address }} - {% endif %} -
      -
      -
      -
      -
      - {% endwith %} -
      - -
      -
      -
      -
       
      -
       
      + +
      +
      +
      + < +
      {{ days.15|date:"F"}}’{{ days.15|date:"y"}}
      + > +
      +
      +
      +
      +
      + {% with events=events %} + + + + {% for day in days %} + {% ifnotequal day current_day %} + + {% else %} + + {% endifnotequal %} + {% endfor %} + + + + + {# первый ряд с отображениями дней где нет событий #} + + {% for day in days %} + {% if day_colspan|get_item:day|get_item:'event' %} + {% ifnotequal day current_day %} + + {% else %} + + {% endifnotequal %} + {% else %} + {% if day_colspan|get_item:day|get_item:'counter' %} + {# здесь ячейка с днями без событий #} + + {% endif %} + {% endif %} + {% endfor %} + + + {% for day in days %} + {% ifnotequal day current_day %} + + {% else %} + + {% endifnotequal %} + {% endfor %} + + {% for event in events %} + + {% for day in days %} + {% if event|in_event:day %} + {% if day.month == event.data_begin.month %} + {% if day.day == event.data_begin.day %} + + {% endif %} + {% else %} + {% comment %} + {% if day.day == event.data_end.day %} + + {% endif %} + {% endcomment %} + + {% endif %} + {% else %} + {% ifnotequal day current_day %} + + {% else %} + + {% endifnotequal %} + + {% endif %} + {% endfor %} + + + {% for day in days %} + {% ifnotequal day current_day %} + + {% else %} + + {% endifnotequal %} + {% endfor %} + + {% endfor %} + +
      {{ day|date:"d" }}/{% if LANGUAGE_CODE == 'ru' %}{{ day|get_rus_day }}{% else %}{{ day|date:"D" }}{% endif %}
      +
      +
      {% trans 'Сегодня' %}
      + {{ day|date:"d" }}/{% if LANGUAGE_CODE == 'ru' %}{{ day|get_rus_day }}{% else %}{{ day|date:"D" }}{% endif %} +
      +
      +
      +
      {% trans "Нет отмеченых событий" %}
      +
      +
      + {% comment %} +
      + {% endcomment %} +
      +
      +

      {{ event.name|safe }}

      +
      +
      + {% if request.user in event.users.all %} + + {% endif %} + +
      +
      {{ event.country }}, {{ event.city }} + {% if event.place %} + , {{ event.place.address.address }} + {% endif %} +
      +
      +
      +
      +
      +
      +
      + +

      {{ event.name|safe }}

      + +
      +
      + {% if request.user in event.users.all %} + + {% endif %} + +
      +
      {{ event.country }}, {{ event.city }} + {% if event.place %} + , {{ event.place.address.address }} + {% endif %} +
      +
      + + +
      +
      +
      + {% endwith %} +
      +
      +
      +
      +
       
      +
       
      {% block scripts %} - - - +{% if request.GET.debug == '1' %} + +{% else %} + +{% endif %} - -{% endblock %} - +{% endblock %} \ No newline at end of file diff --git a/templates/client/includes/accounts/current_user.html b/templates/client/includes/accounts/current_user.html index c6a2a8a0..1d0931a6 100644 --- a/templates/client/includes/accounts/current_user.html +++ b/templates/client/includes/accounts/current_user.html @@ -2,457 +2,490 @@ {% load i18n %} {% load template_filters %} {% load thumbnail %} - -
      -
      - - {# avatar #} - - {# END avatar #} -
      -
      - {# country and city #} -
      - {% if home_form.instance.country %} - - {% else %} - - {% endif %} - {{ home_form.instance.country }} - - - {% if home_form.instance.city %} - - {% else %} - - {% endif %} - , {{ home_form.instance.city }} - - -
      - {% trans 'редактировать' %} -
      -
      {% csrf_token %} -
      - -
      - -
      - {{ home_form.country }} - -
      -
      - -
      - -
      - {{ home_form.city }} -
      -
      - -
      - -
      - -
      -
      - {% trans 'закрыть' %} -
      -
      -
      - {# END country and city #} - - {# name #} -
      - - {{ name_form.get_full_name }} - -
      - {% trans 'редактировать' %} +
      + {# avatar #} +
      - - {# position #} -
      -

      - {{ work_form.position.value }} - {% if work_form.work.value %} - {% trans 'в' %} {{ work_form.work.value }} - {% endif %} -

      - -
      - {% trans 'редактировать' %} -
      -
      {% csrf_token %} - -
      - -
      - -
      - {{ work_form.position }} -
      -
      - -
      - -
      - {{ work_form.work }} -
      -
      - -
      - -
      - -
      -
      - - {% trans 'закрыть' %} -
      -
      -
      - {# END position #} -
      - -
      -
      -
      -
        -
      • - {% if social_form.facebook.value %} - - Facebook - - {% else %} - Facebook - {% endif %} -
      • -
      • - {% if social_form.linkedin.value %} - - LinkedIn - - {% else %} - LinkedIn - {% endif %} - -
      • - {% if social_form.vk.value %} - - В контакте - - {% else %} - В контакте - {% endif %} -
      • - -
      • - {% if social_form.twitter.value %} - - Twitter - - {% else %} - Twitter - {% endif %} -
      • -
      - +
      +
      {{ user.rating }}
      +
      +

      Заполните свой
      профиль, чтобы
      повысить рейтинг

      +

      Чем выше
      рейтинг —
      тем больше
      преимуществ!

      +
      + + {# END avatar #} +
      +
      + {# country and city #} +
      + +
      + + {{ home_form.instance.country }}, {{ home_form.instance.city }} + +
      + {% trans 'редактировать' %}
      -
      {% csrf_token %} - + {% csrf_token %}
      -
      - +
      - {{ social_form.facebook }} + {{ home_form.country }}
      -
      - -
      - {{ social_form.linkedin }} -
      + +
      + {{ home_form.city }} +
      - +
      +
      + +
      +
      + {% trans 'закрыть' %} +
      +
      +
      +
      + {# END country and city #} + {# name #} +
      + +
      + + {{ name_form.get_full_name }} + +
      + {% trans 'редактировать' %} +
      +
      {% csrf_token %} +
      - +
      - {{ social_form.vk }} + {{ name_form.first_name }}
      -
      - +
      - {{ social_form.twitter }} + {{ name_form.last_name }}
      -
      -
      + {% trans 'закрыть' %} +
      +
      +
      +
      + {# END name #} +
      + {# position #} +
      + +
      +

      + {{ work_form.position.value }} + {% if work_form.work.value %} + {% trans 'в' %} {{ work_form.work.value }} + {% endif %} +

      +
      + {% trans 'редактировать' %} +
      +
      {% csrf_token %} +
      +
      + +
      + {{ work_form.position }} +
      +
      + +
      + +
      + {{ work_form.company }} +
      +
      - {% trans 'закрыть' %} +
      +
      + +
      +
      + {% trans 'закрыть' %} +
      +
      +
      +
      + {# END position #} +
      +
      +
      +
      {% trans 'Профили в соц.сетях:' %}
      +
      + -
      -
      - {# contacts #} - - -
      - {# about #} -
      -
      {% trans 'О себе:' %}
      - -
      -

      {{ about_form.about.value }}

      - -
      - {% trans 'редактировать' %} -
      -
      {% csrf_token %} - -
      - -
      - -
      - {{ about_form.about }} -
      -
      - -
      - -
      - -
      -
      - - {% trans 'закрыть' %} -
      -
      -
      -
      - {# END about #} +
      + {% endcomment %} +
      + +
      + + {% if web_page_form.web_page.value %} + {{ web_page_form.web_page.value }} + {% endif %} + +
      + {% trans 'редактировать' %} +
      +
      {% csrf_token %} +
      +
      + +
      + {{ web_page_form.web_page }} +
      +
      +
      +
      + +
      +
      -
      -
      + {% trans 'закрыть' %} +
      +
      +
      +
      + {# END contacts #} +
      +
      +
      + {# about #} +
      +
      {% trans 'О себе:' %}
      +
      + +
      +
      {{ about_form.about.value|linebreaks }}
      +
      + {% trans 'редактировать' %} +
      +
      {% csrf_token %} +
      +
      + +
      + {{ about_form.about }} +
      +
      +
      +
      + +
      +
      + {% trans 'закрыть' %} +
      +
      +
      +
      +
      + {# END about #} + {# companies #} +
      +
      {% trans 'Мои компании:' %}
      + {% if request.user.created_company.all %} + {% else %} +
      + + + + {% trans 'Пока не добавлено ни одной компании' %} +
      + {% endif %} + {% with companies=request.user.created_company.all %} + {% for company in companies %} + + {% endfor %} + {% endwith %} +
      + + {# END companies #} +
      +
      - {% block scripts %} - - - - +{% if request.GET.debug == '1' %} +{% else %} + +{% endif %} {% endblock %} \ No newline at end of file diff --git a/templates/client/includes/accounts/simple_user.html b/templates/client/includes/accounts/simple_user.html index 0af9aa08..df898890 100644 --- a/templates/client/includes/accounts/simple_user.html +++ b/templates/client/includes/accounts/simple_user.html @@ -1,78 +1,91 @@ {% load static %} {% load i18n %} {% load template_filters %} +{% load thumbnail %} - -
      +
      -
      - {% if member.profile.country %} - {{ member.profile.country }}, {{ member.profile.city }} - {% endif %} -
      + {% if member.profile.country or member.profile.city%} +
      + {% if member.profile.country %}{{ member.profile.country }},{% endif %}{% if member.profile.city %} {{ member.profile.city }}{% endif %} +
      + {% endif %}
      {{ member.get_full_name }}
      -
      {{ member.profile.position }} +
      {{ member.position }} {% if member.company %} в “{{ member.company }}” {% else %} {{ member.profile.work }} {% endif %}
      - + {% comment %}
      {{ member.profile.about_company|safe }}
      + {% endcomment %}
      - {% if user.is_authenticated %} - {% trans 'отправить сообщение' %} - {% endif %}
        {% if member.profile.facebook %} -
      • Facebook
      • +
      • + Facebook +
      • {% endif %} {% if member.profile.linkedin %} -
      • LinkedIn
      • +
      • + LinkedIn +
      • {% endif %} {% if member.profile.vk %} -
      • В контакте
      • +
      • + В контакте +
      • {% endif %} {% if member.profile.twitter %} -
      • Twitter
      • +
      • + Twitter +
      • {% endif %}
      -
      - + {% if user.is_authenticated %} + {% trans 'отправить сообщение' %} + {% endif %} +
      @@ -82,22 +95,28 @@
      {% trans 'О себе' %}:
      - {{ member.profile.about|safe }} + {{ member.profile.about|safe|linebreaks }}
      + {% if member.get_expositions_number > 0 or member.get_conferences_number > 0 or member.get_seminars_number > 0 %}
      + {% endif %}
      \ No newline at end of file diff --git a/templates/client/includes/announces.html b/templates/client/includes/announces.html index a844f5ee..722b2356 100644 --- a/templates/client/includes/announces.html +++ b/templates/client/includes/announces.html @@ -1,11 +1,15 @@ {% load i18n %} +{% comment %} + \ No newline at end of file +
      +{% endcomment %} diff --git a/templates/client/includes/article/article_logo.html b/templates/client/includes/article/article_logo.html index 5db40983..06faa278 100644 --- a/templates/client/includes/article/article_logo.html +++ b/templates/client/includes/article/article_logo.html @@ -2,7 +2,7 @@ {% load thumbnail %} {% if obj.logo %} - {% thumbnail obj.logo "100x100" crop="center" as im %} + {% thumbnail obj.logo "100x100" format="PNG" as im %} {% endthumbnail %} {% else %} diff --git a/templates/client/includes/article/article_on_main_preview.html b/templates/client/includes/article/article_on_main_preview.html new file mode 100644 index 00000000..38fbc781 --- /dev/null +++ b/templates/client/includes/article/article_on_main_preview.html @@ -0,0 +1,11 @@ +{% load static %} +{% load thumbnail %} + + +{% if obj.get_blog_preview %} + {% thumbnail obj.get_blog_preview.file_path "220x100" as im %} + + {% endthumbnail %} +{% else %} + +{% endif %} \ No newline at end of file diff --git a/templates/client/includes/article/article_preview.html b/templates/client/includes/article/article_preview.html index 1d7ba514..32e86582 100644 --- a/templates/client/includes/article/article_preview.html +++ b/templates/client/includes/article/article_preview.html @@ -1,10 +1,12 @@ {% load static %} {% load thumbnail %} -{% if obj.logo %} - {% thumbnail obj.logo "250x180" crop="center" as im %} +{% if obj.get_blog_preview %} + {% thumbnail obj.get_blog_preview2.file_path "250x180" as im %} {% endthumbnail %} {% else %} - +
      + +
      {% endif %} \ No newline at end of file diff --git a/templates/client/includes/article/blog_list.html b/templates/client/includes/article/blog_list.html new file mode 100644 index 00000000..9b937c76 --- /dev/null +++ b/templates/client/includes/article/blog_list.html @@ -0,0 +1,16 @@ +
      +
      +
      + {% for blog in object_list %} +
      +
      + {% include 'includes/article/article_preview.html' with obj=blog %} +

      {{ blog.main_title }}

      + {{ blog.preview|safe }} + {{ blog.created|date:"d E Y" }}{% if blog.tag.all.exists %}{% include 'includes/article_tags.html' with obj=blog %}{% endif %} +
      +
      + {% endfor %} +
      +
      +
      diff --git a/templates/client/includes/article/catalog_filter_period.html b/templates/client/includes/article/catalog_filter_period.html new file mode 100644 index 00000000..d6dcdd2b --- /dev/null +++ b/templates/client/includes/article/catalog_filter_period.html @@ -0,0 +1,19 @@ +{% load i18n %} +{% load template_filters %} +{% load tempalte_tags %} + + +{% if month or year %} +{% else %} + {% get_date_reverse %} +
      +
      +
      {% trans 'Период' %}:
      + {% with path=request.path|without_page now=now %} + {% for month in monthes_period %} + {{ month.name|lower }} {{ month.date|date:'Y' }}{% if month != monthes_period|last %},{% endif %} + {% endfor %} + {% endwith %} +
      +
      +{% endif %} diff --git a/templates/client/includes/article/news_list.html b/templates/client/includes/article/news_list.html new file mode 100644 index 00000000..2bd1af8e --- /dev/null +++ b/templates/client/includes/article/news_list.html @@ -0,0 +1,15 @@ +
      +
      + {% for news in object_list %} +
      +
      + + {% include 'includes/article/news_preview.html' with obj=news %} +

      {{ news.main_title }}

      + {{ news.preview }} + {{ news.publish_date|date:"d E Y" }}{% with event=news.get_event %}{% if event %}{{ event.name }}{% endif %}{% endwith %} +
      +
      + {% endfor %} +
      +
      \ No newline at end of file diff --git a/templates/client/includes/article/news_on_main_logo.html b/templates/client/includes/article/news_on_main_logo.html new file mode 100644 index 00000000..51e2920d --- /dev/null +++ b/templates/client/includes/article/news_on_main_logo.html @@ -0,0 +1,10 @@ +{% load static %} +{% load thumbnail %} + +{% if obj.logo %} + {% thumbnail obj.logo "80x80" format="PNG" as im %} + + {% endthumbnail %} +{% else %} + +{% endif %} \ No newline at end of file diff --git a/templates/client/includes/article/news_preview.html b/templates/client/includes/article/news_preview.html index da3d9686..5b85ff8f 100644 --- a/templates/client/includes/article/news_preview.html +++ b/templates/client/includes/article/news_preview.html @@ -2,7 +2,7 @@ {% load thumbnail %} {% if obj.logo %} - {% thumbnail obj.logo "70x70" crop="center" as im %} + {% thumbnail obj.logo "70x70" format="PNG" as im %} {% endthumbnail %} {% else %} diff --git a/templates/client/includes/article_tags.html b/templates/client/includes/article_tags.html index b4c4650a..32ab461c 100644 --- a/templates/client/includes/article_tags.html +++ b/templates/client/includes/article_tags.html @@ -1,4 +1,6 @@ - -{% for tag in obj.tag.all %} -{{ tag.name }}, -{% endfor %} \ No newline at end of file + +{% with tags=obj.tag.all %} + {% for tag in obj.tag.all %} + {{ tag.name }}{% if forloop.counter != tags|length %},{% endif %} + {% endfor %} +{% endwith %} \ No newline at end of file diff --git a/templates/client/includes/booking_block.html b/templates/client/includes/booking_block.html index fa318eaf..8de59a1a 100644 --- a/templates/client/includes/booking_block.html +++ b/templates/client/includes/booking_block.html @@ -42,7 +42,8 @@ {{ hotel.name }} -
      6 500 руб./ночь
      +
       
      + Забронировать
      diff --git a/templates/client/includes/calendar_button.html b/templates/client/includes/calendar_button.html index ef495503..aa0534c6 100644 --- a/templates/client/includes/calendar_button.html +++ b/templates/client/includes/calendar_button.html @@ -1,18 +1,5 @@ {% load i18n %} {% load template_filters %} -{% comment %} -{% if user.is_authenticated %} - {% if event|in_calendar:user %} - - {% trans 'из расписания' %} - {% else %} - {% trans 'в расписание' %} - - {% endif %} -{% else %} - {% trans 'в расписание' %} - -{% endif %} -{% endcomment %} -{% if obj|in_calendar:request.user %}{% trans 'Из расписания' %}{% else %}{% trans 'В расписание' %}{% endif %} + +{% if obj|in_calendar:request.user %}{% trans 'Из расписания' %}{% else %}{% trans 'В расписание' %}{% endif %} diff --git a/templates/client/includes/catalog_paginator.html b/templates/client/includes/catalog_paginator.html index 5942ea5a..89e05474 100644 --- a/templates/client/includes/catalog_paginator.html +++ b/templates/client/includes/catalog_paginator.html @@ -8,38 +8,38 @@
      Показано {{ page_obj.start_index }} - {{ page_obj.end_index }} (всего {{ page_obj.paginator.count }} позиций)
      {% if page_obj.has_previous %} - Предыдущая + Предыдущая {% else %} Предыдущая {% endif %} {% if page_obj.has_next %} - Следующая + Следующая {% else %} Следующая {% endif %} diff --git a/templates/client/includes/catalog_search.html b/templates/client/includes/catalog_search.html index dbfd94df..8da880e7 100644 --- a/templates/client/includes/catalog_search.html +++ b/templates/client/includes/catalog_search.html @@ -1,82 +1,78 @@ {% load static %} {% load i18n %} - -
      -
      -
      {{ search_form.title }}
      -
      -
      -
      -
      - -
      {{ search_form.q }}
      -
      + +
      @@ -96,20 +92,28 @@
      -
      - - + {% block scripts %} - + {% if request.GET.debug == '1' %} + + {% else %} + + {% endif %} - {% endblock %}
      diff --git a/templates/client/includes/catalog_search_main.html b/templates/client/includes/catalog_search_main.html index 9989404d..8dcf2b0c 100644 --- a/templates/client/includes/catalog_search_main.html +++ b/templates/client/includes/catalog_search_main.html @@ -1,13 +1,10 @@ {% load static %} {% load i18n %} -
      -
      {% block scripts %} - + {% if request.GET.debug == '1' %} + + {% else %} + + {% endif %} diff --git a/templates/client/includes/company/company_edit.html b/templates/client/includes/company/company_edit.html index 0f033237..4c72783a 100644 --- a/templates/client/includes/company/company_edit.html +++ b/templates/client/includes/company/company_edit.html @@ -1,583 +1,604 @@ {% load static %} {% load i18n %} {% load template_filters %} +{% load thumbnail %} +
      +
      + +
      +
      +
      + +
      + + {{ home_form.instance.country }}, {{ home_form.instance.city }} + +
      + {% trans 'редактировать' %} +
      +
      {% csrf_token %} +
      +
      + +
      + {{ home_form.country }} +
      +
      +
      + +
      + {{ home_form.city }} +
      +
      +
      +
      + +
      + закрыть +
      +
      +
      +
      +
      + +
      + +
      + {{ name_form.name.value }} +
      + редактировать +
      +
      {% csrf_token %} + +
      -
      -
      - - - -
      -
      - - - -
      - {{ name_form.name.value }} - -
      - редактировать -
      -
      {% csrf_token %} - -
      - -
      - -
      - {{ name_form.name }} -
      -
      - -
      - -
      - -
      -
      - - закрыть -
      -
      -
      -
      - - - - -
      - {% for th in request.user.company.theme.all %} - {{ th.name }}{% ifnotequal forloop.counter request.user.company.theme.all|length %},{% endifnotequal %} - {% endfor %} -
      - -
      - - - - -
      - - - -
      +
      + +
      + {{ name_form.name }} +
      +
      -
      +
      -
      -
      +
      + +
      + -
      Добавить профили в соц.сетях:
      + закрыть +
      +
      +
      +
      +
      +
      + +
      + {{ spec_form.specialization.value }}  +
      + {% trans 'редактировать' %} +
      +
      {% csrf_token %} +
      +
      + +
      + {{ spec_form.specialization }} +
      +
      - -
      - Добавить +
      + +
      + -
      +
      +
      +
      + {% with themes=company.theme.all %} +
      +
      +

      Тематика:

      +
      +
      +
      +
      + {% csrf_token %} +
      {{ theme_form.theme }}
      +
      +
      + +
      +
      + {% endwith %} +
      +
      +  Раскрыть карту + +
      + {{ address_form.address_inf.value }}  +
      + {% trans 'редактировать' %} +
      +
      {% csrf_token %} + +
      + +
      + + {{ address_form.address_inf }} +
      +
      +
      + +
      +
      + + закрыть +
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      {% trans 'Профили в соц.сетях:' %}
      +
      +
    + +
    +
    +
    +
     
    + {% csrf_token %} +
    +
    + +
    + {{ social_form.facebook }} +
    +
    +
    + +
    + {{ social_form.linkedin }} +
    +
    +
    + +
    + {{ social_form.vk }} +
    +
    +
    + +
    + {{ social_form.twitter }} +
    - -
    - -
    - {{ social_form.linkedin }} -
    +
    +
    - -
    - -
    - {{ social_form.vk }} + + {% trans 'закрыть' %} +
    +
    +
    +
    +
    + + Предварительный просмотр +
    + {% block pre_scripts %} - - + + {% endblock %} - {% block scripts %} - - - - - +{% if request.GET.debug == '1' %} +{% else %} + +{% endif %} {% endblock %} diff --git a/templates/client/includes/company/company_list.html b/templates/client/includes/company/company_list.html index dec449a1..9147a93a 100644 --- a/templates/client/includes/company/company_list.html +++ b/templates/client/includes/company/company_list.html @@ -20,7 +20,7 @@
    {% if company.country %}
    @@ -41,13 +41,15 @@ {% if company.get_events %} {% trans 'события' %} ({{ company.get_events_number }}) {% endif %} + {% comment %} {% trans 'заметка' %} + {% endcomment %}
    - + {% endcomment %}
    diff --git a/templates/client/includes/company/company_object.html b/templates/client/includes/company/company_object.html index 76f9d4ae..57bb11b5 100644 --- a/templates/client/includes/company/company_object.html +++ b/templates/client/includes/company/company_object.html @@ -1,66 +1,103 @@ {% load static %} {% load i18n %} {% load template_filters %} - - +{% load thumbnail %} {% block page_body %} -
    +
    {{ company.name|safe }}
    +
    + + {{ company.country.name }}, {{ company.city.name }} + +
    -
    - {{ company.description|safe }} -
    - - +
    + {{ company.specialization|linebreaks }} +
    + {% with themes=company.theme.all %} +
    + {% for th in themes %} + {{ th.name }}{% ifnotequal forloop.counter themes|length %},{% endifnotequal %} + {% endfor %} +
    + {% endwith %}
    - {% if company.address %} - {% with address=company.address %} - {% include 'includes/address_block.html' %} - {% endwith %} -
    - {% endif %} -
    - {% with obj=company filter=filter %} - {% include 'includes/show_tags.html' %} - {% endwith %} -
    -
    + {% if company.address_inf %} +
    +  Раскрыть карту +
    + {{ company.address_inf }} +
    + +
    +
    + {% endif %} + {% if company.tag.all|length > 0 %} +
    + {% with tags=company.tag.all %} + {% for tag in tags %} + {{ tag.name }}, + {% endfor %} + {% endwith %} + +
    +
    + {% endif %}
    + {% if company.facebook or company.linkedin or company.vk or company.twitter %}
    - -
      - {% if company.facebook %} -
    • Facebook
    • - {% endif %} - {% if company.linkedin %} -
    • LinkedIn
    • - {% endif %} - {% if company.vk %} -
    • В контакте
    • - {% endif %} - {% if company.twitter %} -
    • Twitter
    • - {% endif %} -
    -
    + {# {% trans 'отправить сообщение' %} #} + +
    {% trans 'Профили в соц.сетях:' %}
    +
      + {% if company.facebook %} +
    • + Facebook +
    • + {% endif %} + {% if company.linkedin %} +
    • + LinkedIn +
    • + {% endif %} + {% if company.vk %} +
    • + В контакте +
    • + {% endif %} + {% if company.twitter %} +
    • + Twitter +
    • + {% endif %} +
    +
    + {% endif %}
    + {% if company.foundation or company.staff_number or company.description %}
    +
    {% trans 'Дополнительная информация' %}
    @@ -96,27 +135,41 @@ {% endif %} {% if company.description %}
    {% trans 'О компании:' %}
    -
    {{ company.description|safe }}
    +
    {{ company.description|safe|linebreaks }}
    {% endif %} -
    + {% endif %} -
    + +
    -
    -
    -
    -
    {% trans 'Участие в событиях' %}
    - - -
    + +
    + {% if company.get_expositions_number > 0 or company.get_conferences_number > 0 or company.get_seminars_number > 0 %} +
    +
    + +
    {% trans 'Участие в событиях' %}
    + +
    + {% if company.get_expositions_number > 0 %} + {{ company.get_expositions_number }} в {% trans 'выставках' %} + {% endif %} + {% if company.get_conferences_number > 0 %} + {{ company.get_conferences_number }} в {% trans 'конференциях' %} + {% endif %} + {% if company.get_seminars_number > 0 %} + {{ company.get_seminars_number }} в {% trans 'семинарах' %} + {% endif %} + +
    + + +
    + {% endif %}
      {% for event in company.get_events %}
    • @@ -160,42 +213,134 @@ {% endfor %}
    {% if company.get_events %} - {% trans 'Все события' %} + {% trans 'Все события' %} {% endif %}
    -
    -
    - - - + {% if company.get_expositions_number > 0 or company.get_conferences_number > 0 or company.get_seminars_number > 0 %} +
    + {% endif %} + {% if company.users.all|length > 0 %} +
    +
    {% trans 'Сотрудники' %}
    - {% if company.users.all|length > 5 %} - {% trans 'Все сотрудники' %} - {% endif %} -
    -
    + + + {% if company.users.all|length > 5 %} + {% trans 'Все сотрудники' %} + {% endif %} +
    + {% endif %} + + + {% endblock %} \ No newline at end of file diff --git a/templates/client/includes/event_steps.html b/templates/client/includes/event_steps.html index fb222c11..2c54a0cc 100644 --- a/templates/client/includes/event_steps.html +++ b/templates/client/includes/event_steps.html @@ -1,25 +1,37 @@ {% load i18n %}
    -
    {% trans 'Посетить выставку' %}
    +
    {% if event.catalog == '/expo/' %}{% trans 'Участвовать в выставке' %}{% else %}{% trans 'Посетить конференцию' %}{% endif %}
    \ No newline at end of file diff --git a/templates/client/includes/exposition/catalog_filter_period.html b/templates/client/includes/exposition/catalog_filter_period.html index 5eb0825f..daea8cca 100644 --- a/templates/client/includes/exposition/catalog_filter_period.html +++ b/templates/client/includes/exposition/catalog_filter_period.html @@ -8,7 +8,7 @@ {% get_date %}
    -
    Период:
    +
    {% trans 'Период' %}:
    {% with path=request.path|without_page now=now %} {% for month in monthes_period %} {{ month.name|lower }} {{ month.date|date:'Y' }}{% if month != monthes_period|last %},{% endif %} @@ -17,7 +17,7 @@
    {% endif %} diff --git a/templates/client/includes/exposition/exposition_list.html b/templates/client/includes/exposition/exposition_list.html index db448eb1..b0cbcd8f 100644 --- a/templates/client/includes/exposition/exposition_list.html +++ b/templates/client/includes/exposition/exposition_list.html @@ -1,129 +1,141 @@ {% load static %} {% load i18n %} {% load template_filters %} -
      - {% with objects=object_list %} - {% for obj in objects %} -
    • -
    • + - - -
      -
      - - - {% if obj.quality_label.ufi.is_set %} -
      - -
      - {% endif %} - - -
      - -
      -
      - {{ obj.main_title|safe }} -
      -
      - -
      - -
      - {% with obj=obj %} - {% include 'client/includes/show_date_block.html' %} - {% endwith %} -
      - - {% if obj.country %} -
      - {{ obj.country }}, {{ obj.city }}, - - {% if obj.place %} - {{ obj.place }} - {% endif %} -
      - {% endif %} -
      -
      - - -
      -
      - {% include 'client/includes/exposition/services.html' with obj=obj %} - - {% include 'client/includes/calendar_button.html' with event=obj user=user %} -
      - {% with note=obj|note_by_user:request.user %} - {% trans 'заметка' %} -
      -
      - -
      -
      - {% endwith %} -
      - {% if request.user.is_admin %} - - {% endif %} -
      - -
      - -
      - {% include 'client/buttons/booking_button.html' with object=obj %} -
      -
      - - -
      -
      - {% if obj.visitors %} - {{ obj.visitors }} - {% endif %} - {% if obj.members %} - {{ obj.members }} - {% endif %} -
      -
      - {% include 'client/includes/exposition/tags.html' with obj=obj %} -
      -
      -
    • - - {% endfor %} - {% endwith %} +
      +
      + {% if obj.quality_label.ufi.is_set %} +
      + +
      + {% endif %} +
      + +
      +
      + {{ obj.main_title|safe }} +
      +
      +
      +
      + {% with obj=obj %} + {% include 'client/includes/show_date_block.html' %} + {% endwith %} +
      + {% if obj.country %} +
      + {{ obj.country }}, {{ obj.city }} + {% if obj.place %} + , {{ obj.place }} + {% endif %} +
      + {% endif %} +
      +
      +
      +
      + {% include 'client/includes/exposition/services.html' with obj=obj %} + {% include 'client/includes/calendar_button.html' with obj=obj%} +
      + {% with note=obj|note_by_user:request.user %} + {% trans 'заметка' %} +
      +
      + +
      +
      + {% endwith %} +
      + {% if request.user.is_admin %} + + {% endif %} +
      +
      +
      + {% include 'client/buttons/booking_button.html' with object=obj %} +
      +
      + +
      +
      + {% if obj.visitors %} + {{ obj.visitors }} + {% endif %} + {% if obj.members %} + {{ obj.members }} + {% endif %} +
      +
      + {% include 'client/includes/exposition/tags.html' with obj=obj %} +
      +
      + + + + {% if forloop.counter == 8 %} + + + {%endif %} + {% endfor %} + {% endwith %}
    {% block scripts %} - - +{% else %} + +{% endif %} {% endblock %} \ No newline at end of file diff --git a/templates/client/includes/exposition/exposition_object.html b/templates/client/includes/exposition/exposition_object.html index 5dfe44ca..15745390 100644 --- a/templates/client/includes/exposition/exposition_object.html +++ b/templates/client/includes/exposition/exposition_object.html @@ -2,412 +2,397 @@ {% load i18n %} {% load thumbnail %} {% load template_filters %} - {% block page_body %} -
    -
    - - -
    -
    -
    - {% if exposition.main_title %} - {{ exposition.main_title|safe }} {{ exposition.name|safe }} - {% else %} - {{ exposition.name|safe }} - {% endif %} -
    -
    - -
    - {% with obj=exposition %} - {% include 'client/includes/show_date_block.html' %} - {% endwith %} -
    - {% if exposition.place %} -
    -
    -
    - {{ exposition.place.adress }} -
    - -
    - - -
    - {% endif %} -
    -
    -
    - {% with event=exposition user=user %} - {% include 'client/includes/visit_button.html' %} - {% endwith %} - - {% with event=exposition user=user %} - {% include 'client/includes/calendar_button.html' %} - {% endwith %} -
    - - - {% trans 'заметка' %} -
    -
    - -
    -
    -
    - {% if request.user.is_admin %} - {% trans 'изменить' %} - {% endif %} - -
    - - - -
    -
    -
    -
    - -
    - -
    - {% with tags=exposition.tag.all %} - {% for tag in tags %} - {{ tag.name }}, - {% endfor %} - {% endwith %} - -
    -
    -
    -
    - {% include 'client/includes/exposition/exposition_services.html' %} - - {% include 'includes/event_steps.html' with event=exposition %} - - {% if exposition.get_photos %} - {% with photos=exposition.get_photos|slice:"5" %} -
    - -
    - - + {% endwith %} + {% endif %} + {% if exposition.description %} +
    +
    {% trans 'О выставке' %} {{ exposition.name|safe }}
    +
    {{ exposition.description|safe|linebreaks }}
    +
    +
    + {% endif %} +
    +
    {% trans 'Дополнительная информация' %}
    + +
    + {% if exposition.organiser.all|length > 0 %} +
    {% trans 'Организатор' %}:
    +
    + {% with organisers=exposition.organiser.all %} + {% for organiser in organisers %} + {{ organiser.name }}
    + {% endfor %} + {% endwith %} +
    + {% endif %} + {% if exposition.web_page %} +
    {% trans 'Веб-сайт' %}:
    +
    + {{ exposition.web_page }} +
    + {% endif %} + {% if exposition.get_audience %} +
    {% trans 'Аудитория' %}:
    +
    + {{ exposition.get_audience }} +
    + {% endif %} + {% if exposition.get_periodic %} +
    {% trans 'Периодичность' %}:
    +
    {{ exposition.get_periodic }}
    + {% endif %} + {% if exposition.products %} +
    {% trans 'Экспонируемые продукты' %}:
    +
    {{ exposition.products|safe }}
    + {% endif %} + {% if exposition.time %} +
    {% trans 'Время работы' %}:
    +
    {{ exposition.time|safe }}
    + {% endif %} +
    +
    + +
    +
    + +
    +
    + +
    +
    + {% with companies=exposition.company.all|slice:":6" %} + {% if companies %} + {# есть участники #} +
    +
    {% trans 'Участники' %}
    + + {% trans 'Все участники' %} +
    + + {% else %} + {# нет участников #} +
    +
    {% trans 'Участники' %}
    +

    {% trans 'Привлекайте целевых посетителей на стенд' %}

    +

    Рекламировать участника

    +
    + {% endif %} + {% endwith %} +
    +
    + {% with visitors=exposition.users.all|slice:":17" %} +
    +
    {% trans 'Посетители' %}
    +
    + + {% trans 'Все посетители' %} + {% endwith %} +

    {% trans 'Пока никто не отметился на событии.' %}

    + {% with event=exposition user=user %} + {% include 'client/includes/visit_button.html' %} + {% endwith %} +
    +
    +
    + {% if exposition.area %} + {% else %} + {% if exposition.members or exposition.visitors or exposition.foundation_year %} +

     Статистика

    + {% endif %} + {% endif %} + {% if exposition.members or exposition.visitors or exposition.foundation_year or exposition.area %} +
    + {% if exposition.area %} +
    +
    {% trans 'Общая выставочная площадь' %}
    +
    + {{ exposition.area }} {% trans 'м²' %} +
    +
    + {% endif %} +
    + {% if exposition.members %} +
    {{ exposition.members }} {% trans 'участников' %}
    + {% endif %} + {% if exposition.visitors %} +
    {{ exposition.visitors }} {% trans 'посетителей' %}
    + {% endif %} + {% if exposition.foundation_year %} +
    {% trans 'Основано в' %} {{ exposition.foundation_year }} {% trans 'году' %}
    + {% endif %} +
    +
    + {% endif %} +
    + {% include 'client/includes/booking_block.html' with city=exposition.city place=exposition.place %} +
    + {% if exposition.get_nearest_events|slice:":6" %} +
    +
    {% trans 'Ближайшие выставки по тематике' %} «{{ exposition.theme.all.0 }}»
    + +
    + {% endif %} + {% endblock %} {% block content_text %} {% endblock %} +{% block popup %} + {% include 'client/popups/advertise_member.html' with form=advertising_form %} +{% endblock %} {% block scripts %} - +{% if request.GET.debug == '1' %} + +{% else %} + +{% endif %} {% endblock %} \ No newline at end of file diff --git a/templates/client/includes/exposition/exposition_services.html b/templates/client/includes/exposition/exposition_services.html index fb4f7b67..519a9b37 100644 --- a/templates/client/includes/exposition/exposition_services.html +++ b/templates/client/includes/exposition/exposition_services.html @@ -8,10 +8,11 @@
  • {% trans 'Устный переводчик' %}
  • + {% if exposition.country_id not in sng_countries %}
  • - {% trans 'Бизнес-тур "под ключ"' %}
  • + {% endif %}
  • {% trans 'Заочное посещение' %}
  • diff --git a/templates/client/includes/exposition/price.html b/templates/client/includes/exposition/price.html index 32d9a165..c3dcd52a 100644 --- a/templates/client/includes/exposition/price.html +++ b/templates/client/includes/exposition/price.html @@ -88,13 +88,27 @@ {% if exposition.price_day %}
  • -
    {{ exposition.price_day }} {{ exposition.get_currency_html }}
    +
    + {% if exposition.price_day|isdigit %} + {{ exposition.price_day }} + {% else %} + {{ exposition.price_day }} + {% endif %} + {% if exposition.price_day|isdigit %}{{ exposition.get_currency_html }}{% endif %} +
    {% trans 'на 1 день' %}
  • {% endif %} {% if exposition.price_all %}
  • -
    {{ exposition.price_all }} {{ exposition.get_currency_html }}
    +
    + {% if exposition.price_day|isdigit %} + {{ exposition.price_all }} + {% else %} + {{ exposition.price_all }} + {% endif %} + {% if exposition.price_all|isdigit %}{{ exposition.get_currency_html }}{% endif %} +
    {% trans 'на все дни' %}
  • {% endif %} @@ -113,7 +127,7 @@
      {% if exposition.price_day_bar %}
    • -
      {{ exposition.price_day_bar }} {{ exposition.get_currency_html }}
      +
      {{ exposition.price_day_bar }} {% if exposition.price_day_bar|isdigit %}{{ exposition.get_currency_html }}{% endif %}
      на 1 день
    • @@ -122,7 +136,7 @@
    • {# {% if exposition.price_all_bar|isdigit %} #} -
      {{ exposition.price_all_bar }} {{ exposition.get_currency_html }}
      +
      {{ exposition.price_all_bar }} {% if exposition.price_all_bar|isdigit %}{{ exposition.get_currency_html }}{% endif %}
      {% trans 'на все дни' %}
    • @@ -137,16 +151,17 @@
      + {% if exposition.get_audience %}
      {% trans 'Выставка открыта для' %}:
        {{ exposition.get_audience }}
      + {% endif %}
      -
    @@ -154,63 +169,69 @@
    {% trans 'Стоимость аренды 1м²' %}
    -
      - {% if exposition.max_closed_equipped_area %} -
    • + {% if exposition.max_closed_equipped_area or exposition.max_closed_area or exposition.max_open_area %} +
        + {% if exposition.max_closed_equipped_area %} +
      • -
        - {% if exposition.min_closed_equipped_area %} - {{ exposition.min_closed_equipped_area }}-{{ exposition.max_closed_equipped_area }} {{ exposition.get_currency_html }} - {% else %} - {{ exposition.max_closed_equipped_area }} {{ exposition.get_currency_html }} - {% endif %} -
        -
        {% trans 'оборудованная площадь' %}
        -
      • - {% endif %} - - {% if exposition.max_closed_area %} -
      • -
        - {% if exposition.min_closed_area %} - {{ exposition.min_closed_area }}-{{ exposition.max_closed_area }} {{ exposition.get_currency_html }} - {% else %} - {{ exposition.max_closed_area }} {{ exposition.get_currency_html }} - {% endif %} -
        -
        {% trans 'необорудованная площадь' %}
        -
      • - {% endif %} - - {% if exposition.max_open_area %} -
      • -
        - {% if exposition.min_open_area %} - {{ exposition.min_open_area }}-{{ exposition.max_closed_area }} {{ exposition.get_currency_html }} - {% else %} - {{ exposition.max_open_area }} {{ exposition.get_currency_html }} - {% endif %} -
        -
        {% trans 'открытая площадь' %}
        -
      • - {% endif %} - -
      - - {% trans 'Заявка на участие' %} - -
      - {% if exposition.min_area %} -

      {% trans 'Минимальный размер стенда' %} — {{ exposition.min_area }}м²

      - {% endif %} - {% if exposition.registration_payment %} -

      {% trans 'Регистрационный взнос' %} — {{ exposition.registration_payment }}{{ exposition.get_currency_html }}

      - {% endif %} - {% if exposition.application_deadline %} -

      {% trans 'Крайний срок подачи заявки' %} — {{ exposition.application_deadline }}

      - {% endif %} - -
      +
      + {% if exposition.min_closed_equipped_area %} + {{ exposition.min_closed_equipped_area }}-{{ exposition.max_closed_equipped_area }} {{ exposition.get_currency_html }} + {% else %} + {{ exposition.max_closed_equipped_area }} {{ exposition.get_currency_html }} + {% endif %} +
      +
      {% trans 'оборудованная площадь' %}
      +
    • + {% endif %} + + {% if exposition.max_closed_area %} +
    • +
      + {% if exposition.min_closed_area %} + {{ exposition.min_closed_area }}-{{ exposition.max_closed_area }} {{ exposition.get_currency_html }} + {% else %} + {{ exposition.max_closed_area }} {{ exposition.get_currency_html }} + {% endif %} +
      +
      {% trans 'необорудованная площадь' %}
      +
    • + {% endif %} + + {% if exposition.max_open_area %} +
    • +
      + {% if exposition.min_open_area %} + {{ exposition.min_open_area }}-{{ exposition.max_open_area }} {{ exposition.get_currency_html }} + {% else %} + {{ exposition.max_open_area }} {{ exposition.get_currency_html }} + {% endif %} +
      +
      {% trans 'открытая площадь' %}
      +
    • + {% endif %} + +
    + {% else %} +

    {% trans 'Цены на площадь доступны по запросу' %}

    + {% endif %} + + {% trans 'Заявка на участие' %} + + {% if exposition.min_stand_size or exposition.registration_payment or exposition.application_deadline %} +
    + {% if exposition.min_stand_size %} +

    {% trans 'Минимальный размер стенда' %} — {{ exposition.min_stand_size }}м²

    + {% endif %} + {% if exposition.registration_payment %} +

    {% trans 'Регистрационный взнос' %} — {{ exposition.registration_payment }}{{ exposition.get_currency_html }}

    + {% endif %} + {% if exposition.application_deadline %} +

    {% trans 'Крайний срок подачи заявки' %} — {{ exposition.application_deadline }}

    + {% endif %} + +
    + {% endif %}
    diff --git a/templates/client/includes/exposition/search_result.html b/templates/client/includes/exposition/search_result.html index a994aee7..a387d86c 100644 --- a/templates/client/includes/exposition/search_result.html +++ b/templates/client/includes/exposition/search_result.html @@ -1,120 +1,106 @@ {% load static %} {% load i18n %} {% load template_filters %} - - +{% block scripts %} +{% if request.GET.debug == '1' %} + +{% else %} + +{% endif %} + +{% endblock %} diff --git a/templates/client/includes/exposition/services.html b/templates/client/includes/exposition/services.html index ef4dfc36..217182c4 100644 --- a/templates/client/includes/exposition/services.html +++ b/templates/client/includes/exposition/services.html @@ -9,6 +9,9 @@
  • {{ service.name }}
  • {% endfor %} {% endwith %} + {% if obj.country_id in sng_countries %} +
  • {% trans 'Заказать отель' %}
  • + {% endif %} \ No newline at end of file diff --git a/templates/client/includes/exposition/statistic.html b/templates/client/includes/exposition/statistic.html index d457a71d..ed72dfda 100644 --- a/templates/client/includes/exposition/statistic.html +++ b/templates/client/includes/exposition/statistic.html @@ -1,4 +1,8 @@ {% load i18n %} +{% load template_filters %} +{% ifequal LANGUAGE_CODE 'ru' %} + {% load pymorphy_tags %} +{% endifequal %}
    @@ -74,68 +78,68 @@ {% with statistics=exposition.statistic.all %} {% for st in statistics %}
    - - -
    - -
    -
    - {{ st.visitors }} -
    {% trans 'посетителей' %}
    -
    -
    - {{ st.members }} -
    {% trans 'учасников' %}
    -
    -
    - -
    - {% if exposition.place %} -
    -
    {% trans 'Общая выставочная площадь' %}
    - -
    {{ st.area }} {% trans 'м' %}2
    - -
    - {% endif %} - -
    {{ exposition.foundation_year }} год основания
    -
    - - -
    + + +
    + +
    +
    + {{ st.visitors }} +
    + {% ifequal LANGUAGE_CODE 'ru' %} + {{ "посетитель"|plural:st.visitors }} + {% else %} + {% trans 'посетителей' %} + {% endifequal %} +
    + +
    +
    + {{ st.members }} +
    + {% ifequal LANGUAGE_CODE 'ru' %} + {{ "участник"|plural:st.members }} + {% else %} + {% trans 'участников' %} + {% endifequal %} +
    +
    +
    + +
    + {% if st.area %} +
    +
    {% trans 'Общая выставочная площадь' %}
    + +
    {{ st.area }} {% trans 'м' %}2
    + +
    + {% endif %} + +
    {{ exposition.foundation_year }} год основания
    +
    + {% if st.countries_number or st.countries %} +
    +
    {% trans 'Страны' %}
    + +
    + {% if st.countries_number %} +
      +
    • {{ st.countries_number }} {% trans 'стран-участниц' %}
    • +
    + {% else %} + {% with html=st.countries|generate_countries_list %} + {{ html|safe }} + {% endwith %} + + {% endif %} + +
    + +
    + {% endif %} + +
    {% endfor %} diff --git a/templates/client/includes/exposition/tags.html b/templates/client/includes/exposition/tags.html index bfde7cc5..71c42583 100644 --- a/templates/client/includes/exposition/tags.html +++ b/templates/client/includes/exposition/tags.html @@ -1,5 +1,5 @@ {% with tags=obj.tags %} {% for tag in tags %} - {{ tag.name }}, + {{ tag.name }}{% if forloop.counter != tags|length %},{% endif %} {% endfor %} {% endwith %} \ No newline at end of file diff --git a/templates/client/includes/exposition/visitors.html b/templates/client/includes/exposition/visitors.html index a242f08f..ecf0a7d2 100644 --- a/templates/client/includes/exposition/visitors.html +++ b/templates/client/includes/exposition/visitors.html @@ -23,16 +23,17 @@
    {{ member.position }}
    + {% comment %} {% if member.country %} {% endif %} + {% endcomment %}
    diff --git a/templates/client/includes/footer.html b/templates/client/includes/footer.html index 47e105d3..95157d36 100644 --- a/templates/client/includes/footer.html +++ b/templates/client/includes/footer.html @@ -5,13 +5,16 @@
    - \ No newline at end of file + diff --git a/templates/client/includes/header.html b/templates/client/includes/header.html index 837234ee..dc82cb48 100644 --- a/templates/client/includes/header.html +++ b/templates/client/includes/header.html @@ -20,6 +20,7 @@ {% endif %}
      + {% for lang in LANGUAGES %}
      {% csrf_token %} @@ -42,7 +43,12 @@
        + {% comment %} +
      • RSS
      • + {% endcomment %} +
      • Instagram' %}
      • +
      • Youtube' %}
      • Facebook' %}
      • LinkedIn' %}
      • В контакте' %}
      • @@ -51,17 +57,15 @@ {% if user.is_authenticated %} diff --git a/templates/client/includes/place/place_object.html b/templates/client/includes/place/place_object.html index 46497fc1..258fef83 100644 --- a/templates/client/includes/place/place_object.html +++ b/templates/client/includes/place/place_object.html @@ -1,356 +1,346 @@ {% load static %} {% load i18n %} {% load template_filters %} - - {% block page_body %} -
        -
        - - -
        -
        -
        - {{ place.name|safe }} -
        -
        - {{ place.description|safe|linebreaks }} -
        - {% trans 'Далее...' %} - - {% if place.address %} -
        -
        -
        - {{ place.adress }} -
        - -
        -
        - +
        +
        +
        + {{ place.name|safe }} +
        +
        + {{ place.description.strip|safe|linebreaks|truncatewords:20 }} +
        + {% trans 'Далее...' %} + + {% if place.address %} +
        +
        +
        + {{ place.adress }} +
        + +
        + -
        - {% else %} -
        - {% endif %} -
        -
        -
        - -
        -
        Услуги
        -
        -
          - {% if place.bank %} -
        • {% trans 'Банк / банкоматы / обмен валюты' %}
        • - {% endif %} - {% if place.wifi %} -
        • Wi-Fi
        • - {% endif %} - {% if place.children_room %} -
        • {% trans 'Детская комната' %}
        • - {% endif %} - {% if place.disabled_service %} -
        • {% trans 'Сервис для инвалидов' %}
        • - {% endif %} -
        -
          - {% if place.conference_centre %} -
        • {% trans 'Конгресс-центр' %}
        • - {% endif %} - {% if place.business_centre %} -
        • {% trans 'Бизнес центр' %}
        • - {% endif %} - {% if place.online_registration %} -
        • {% trans 'Онлайн-регистрация' %}
        • - {% endif %} - {% if place.cafe %} -
        • {% trans 'Кафе и рестораны' %}
        • - {% endif %} -
        -
          - {% if place.terminals %} -
        • {% trans 'Информационные терминалы' %}
        • - {% endif %} - {% if place.parking %} -
        • {% trans 'Парковка' %}
        • - {% endif %} - {% if place.press_centre %} -
        • {% trans 'Пресс-центр' %}
        • - {% endif %} - {% if place.mobile_application %} -
        • {% trans 'Мобильное приложение' %}
        • - {% endif %} -
        -
        -
        -
        - {% if place.photogallery %} - {% with photos=place.photogallery.photos.all|slice:"5" %} -
        -
        {% trans 'Фотогалерея' %}
        - -
        - {% endwith %} - {% endif %} -
        - {% if place.total_area %} -
        +
        + {% else %} +
        + {% endif %} +
        +
        +
        +
        +
        Услуги
        +
        +
          + {% if place.bank %} +
        • {% trans 'Банк / банкоматы / обмен валюты' %}
        • + {% endif %} + {% if place.wifi %} +
        • Wi-Fi
        • + {% endif %} + {% if place.children_room %} +
        • {% trans 'Детская комната' %}
        • + {% endif %} + {% if place.disabled_service %} +
        • {% trans 'Сервис для инвалидов' %}
        • + {% endif %} +
        +
          + {% if place.conference_centre %} +
        • {% trans 'Конгресс-центр' %}
        • + {% endif %} + {% if place.business_centre %} +
        • {% trans 'Бизнес-центр' %}
        • + {% endif %} + {% if place.online_registration %} +
        • {% trans 'Онлайн-регистрация' %}
        • + {% endif %} + {% if place.cafe %} +
        • {% trans 'Кафе и рестораны' %}
        • + {% endif %} +
        +
          + {% if place.terminals %} +
        • {% trans 'Информационные терминалы' %}
        • + {% endif %} + {% if place.parking %} +
        • {% trans 'Парковка' %}
        • + {% endif %} + {% if place.press_centre %} +
        • {% trans 'Пресс-центр' %}
        • + {% endif %} + {% if place.mobile_application %} +
        • {% trans 'Мобильное приложение' %}
        • + {% endif %} +
        +
        +
        +
        + {% if place.photogallery %} + {% with photos=place.photogallery.photos.all|slice:"5" %} +
        +
        {% trans 'Фотогалерея' %}
        + +
        + {% endwith %} + {% endif %} +
        + {% if place.total_area %} +
        {% trans 'Общая выставочная площадь' %}
        {{ place.total_area|int_format }} м²
        -
        - {% endif %} - +
        + {% endif %}
        - {% if place.closed_area %} + {% if place.closed_area %}
        {{ place.closed_area|int_format }} {% trans 'м²' %} {% trans 'закрытая выставочная площадь' %}
        - {% endif %} - {% if place.open_area %} + {% endif %} + {% if place.open_area %}
        {{ place.open_area|int_format }} {% trans 'м²' %} {% trans 'открытая выставочная площадь' %} -
        - {% endif %} +
        + {% endif %}
        - -
        -
        -
          - {% for hall in place.halls.all %} - - {% if not forloop.counter|divisibleby:"2" %} -
        • {{ hall.name }} {% if hall.number %} №{{ hall.number }} {% endif %} — {{ hall.capacity }} м2
        • - {% endif %} - {% endfor %} -
        - -
        -
        -
          - {% for hall in place.halls.all %} - {% if forloop.counter|divisibleby:"2" %} -
        • {{ hall.name }} {% if hall.number %} №{{ hall.number }} {% endif %} — {{ hall.capacity }} м2
        • - {% endif %} - {% endfor %} - -
        -
        -
        - -
        - {{ place.total_year_action }} -
        - -
        - {% if place.foundation_year %} -
        {% trans 'Основано в' %} {{ place.foundation_year }} {% trans 'году' %}
        - {% endif %} -
        - - -
        - {% if place.get_scheme %} -
        -
        -
        {% trans 'Схема павильонов' %}
        - {% for scheme in place.get_scheme %} - - {% ifequal scheme.file_path.url|slice:"-3:" 'pdf' %} - {% trans 'Схема в pdf' %} - {% else %} -
        - {% endifequal %} - -
        - {% endfor %} - -
        - {% endif %} -
        -
        {% trans 'Контактная информация' %}
        -
        -
        -
        {{ place.adress }}
        - -
        - -
        -
          - {% if place.phone %} -
        • {{ place.phone|phone }} ({% trans 'телефон' %})
        • - {% endif %} - {% if place.fax %} -
        • {{ place.fax|phone }} ({% trans 'факс' %})
        • - {% endif %} -
        +
        +
        +
          + {% for hall in place.halls.all %} + {% if not forloop.counter|divisibleby:"2" %} +
        • {{ hall.name }} {% if hall.number %} №{{ hall.number }} {% endif %} — {{ hall.capacity }} м2
        • + {% endif %} + {% endfor %} +
        +
        +
          + {% for hall in place.halls.all %} + {% if forloop.counter|divisibleby:"2" %} +
        • {{ hall.name }} {% if hall.number %} №{{ hall.number }} {% endif %} — {{ hall.capacity }} м2
        • + {% endif %} + {% endfor %} +
        +
        +
        + {% if place.total_year_action %} +
        +
        + {% trans 'Ежегодно проводится' %} +
        +
        + {% if place.total_year_action.isdigit %} + {% ifequal LANGUAGE_CODE 'ru' %} + {% load pymorphy_tags %} + {{ place.total_year_action }} + {{ "событие"|plural:place.total_year_action }} + {% else %} + {{ place.total_year_action }} + {% trans 'событий' %} + {% endifequal %} + + {% else %} + {{ place.total_year_action }} + {% endif %} +
        +
        + {% endif %} + {% if place.foundation_year %} +
        +
        {% trans 'Основано в' %} {{ place.foundation_year }} {% trans 'году' %}
        +
        + {% endif %} +
        + {% if place.get_scheme %} +
        +
        +
        {% trans 'Схема павильонов' %}
        + {% for scheme in place.get_scheme %} + {% ifequal scheme.file_path.url|slice:"-3:" 'pdf' %} + {% trans 'Схема в pdf' %} + {% else %} +
        + {% endifequal %} +
        + {% endfor %} +
        + {% endif %} +
        +
        {% trans 'Контактная информация' %}
        +
        +
        +
        {{ place.adress }}
        + +
        +
          + {% if place.phone %} +
        • {{ place.phone|phone }} ({% trans 'телефон' %})
        • + {% endif %} + {% if place.fax %} +
        • {{ place.fax|phone }} ({% trans 'факс' %})
        • + {% endif %} +
        +
        +
        +
        +
        + {% if place.events %} +
        +
        {% trans 'Список событий' %}
        +
        - {% if place.events %} -
        -
        {% trans 'Список событий' %}
        -
        +
        +
        {% if event.visitors %} {{ event.visitors }}{% endif %} {% if event.members %}{{ event.members }}{% endif %}
        -
        - {% with obj=event %} - {% include 'client/includes/show_tags.html' %} - {% endwith %} -
        + {% with obj=event %} + {% include 'client/includes/show_tags.html' %} + {% endwith %} +
        + {% endfor %} +
      +
      + {% endif %} +
      + {% include 'client/includes/booking_block.html' with city=place.city place=place %} +
      + {% if place.get_nearest_places %} +
      +
      {% trans 'Ближайшие выставочные центры' %}
      + -
      - {% endif %} -
      - {% include 'client/includes/booking_block.html' with city=place.city place=place %} -
      - - {% if place.get_nearest_places %} -
      -
      {% trans 'Ближайшие выставочные центры' %}
      - -
      - {% endif %} - +
    +
    + {% if pl.total_area %} +
    {{ pl.total_area }}
    + {% endif %} + +
    + + + + {% endfor %} + + + {% endif %} {% endblock %} {% block scripts %} - +{% if request.GET.debug == '1' %} + +{% else %} + +{% endif %} {% endblock %} \ No newline at end of file diff --git a/templates/client/includes/services.html b/templates/client/includes/services.html index 11ba9427..262b0832 100644 --- a/templates/client/includes/services.html +++ b/templates/client/includes/services.html @@ -4,10 +4,10 @@ \ No newline at end of file diff --git a/templates/client/includes/show_date_block.html b/templates/client/includes/show_date_block.html index bbdc888c..42343411 100644 --- a/templates/client/includes/show_date_block.html +++ b/templates/client/includes/show_date_block.html @@ -28,7 +28,12 @@ {{ obj.data_begin|date:"F j" }} {% endifequal %} {% else %} - {{ obj.data_begin|date:"j" }}{% endifnotequal %} {% trans 'по' %} {{ obj.data_end }} + {{ obj.data_begin|date:"j" }}{% endifnotequal %} {% trans 'по' %} + {% ifequal LANGUAGE_CODE 'ru' %} + {{ obj.data_end|ru_strftime:"%d %B" }} + {% else %} + {{ obj.data_end }} + {% endifequal %} {% else %} {{ obj.data_begin }} {% endif %} diff --git a/templates/client/includes/show_logo.html b/templates/client/includes/show_logo.html index 900fa744..b4e58509 100644 --- a/templates/client/includes/show_logo.html +++ b/templates/client/includes/show_logo.html @@ -1,4 +1,5 @@ {% load static %} +{% load thumbnail %} {% if obj.get_logo %} {# delete after changing all logos #} @@ -8,5 +9,20 @@ {% endif %} {% else %} - + + {% if obj.logo %} + {% if customSize %} + {% thumbnail obj.logo customSize as im %} + im.width %}class="portrait"{% endif %}/> + {% endthumbnail %} + {% else %} + {% thumbnail obj.logo "100x100" as im %} + + {% endthumbnail %} + {% endif %} + + {% else %} + + + {% endif %} {% endif %} \ No newline at end of file diff --git a/templates/client/includes/side_confs.html b/templates/client/includes/side_confs.html new file mode 100644 index 00000000..bf0009f1 --- /dev/null +++ b/templates/client/includes/side_confs.html @@ -0,0 +1,14 @@ +{% load i18n %} + \ No newline at end of file diff --git a/templates/client/index.html b/templates/client/index.html index 152a84d3..9e4c19dc 100644 --- a/templates/client/index.html +++ b/templates/client/index.html @@ -3,270 +3,164 @@ {% load i18n %} {% load thumbnail %} {% load template_filters %} - +{% block styles %} + +{% endblock %} {% block body_class %} class="main-page" {% endblock %} - {% block top %} +
    +
    -
    -
    - - + - + {% include 'client/includes/index/main_events.html' with events=events %} -
    -
    +
    +
    {% endblock %} - {% block search %} - {% include 'includes/catalog_search_main.html' with search_form=search_form %} + {% include 'includes/catalog_search_main.html' with search_form=search_form %} {% endblock %} - {% block catalog %} -
    -
    - - -
    -
    {% trans 'Выставки' %}
    - - -
    +
    +
    -
    -
    {% trans 'конференции' %}
    - - -
    - -
    -
    {% trans 'семинары' %}
    - - -
    +
    + {% include 'client/includes/index/expos.html' with themes=exposition_themes %} +
    +
    + {% include 'client/includes/index/confs.html' with themes=conference_themes %}
    -
    - {% block menu_banner %} - - - - {% endblock %} -
    +
    + {% block menu_banner %} + + {% endblock %} +
    -
    -{% endblock %} + +
    +{% endblock %} {% block announces %} -
    -
    - +
    +
    + + +
    + -
    -{% endblock %} +
    +
    +{% endblock %} {% block partners %} -
    -
    -
    {% trans 'Наши партнеры:' %}
    -
      -
    • -
    • -
    • -
    • -
    • -
    -
    -
    +
    +
    +
    {% trans 'Наши партнеры:' %}
    +
      +
    • +
    • +
    • +
    • +
    • +
    +
    +
    {% endblock %} - {% block services %} -
    -
    - - - -
    -
    - - -
    -
    -
    +
    +
    + +
    +
    + {% include 'client/includes/index/blogs.html' with blogs=blogs %} + {% comment %} + +
    +
    + {% endcomment %}
    -
    -
    - +
    +
    +{% if request.GET.debug == '1' %} + +{% else %} + +{% endif %} + {% else %} + + {% endif %} + + {% endblock %} \ No newline at end of file diff --git a/templates/client/password_reset/base.html b/templates/client/password_reset/base.html index f5f386bb..6ccdddd8 100644 --- a/templates/client/password_reset/base.html +++ b/templates/client/password_reset/base.html @@ -13,27 +13,33 @@ {% endblock %} {% block content_list %} -
    +
    {% csrf_token %} -

    {{ form.username_or_email.label }}

    +

    {{ form.username_or_email.label }}

    +
    - - {% if form.errors %} - {# если есть ошибка #} -
    - {{ form.username_or_email }} -
    - {{ form.errors.username_or_email.0 }}{# текст ошибки #} - {% else %} - {# ошибки нет #} -
    - {{ form.username_or_email }} -
    - {% endif %} + + {% if form.errors %} + {# если есть ошибка #} +
    + {{ form.username_or_email }} +
    +
    + {{ form.errors.username_or_email.0 }}{# текст ошибки #} +
    + + {% else %} + {# ошибки нет #} +
    + {{ form.username_or_email }} +
    + {% endif %} + +
    diff --git a/templates/client/place/photo.html b/templates/client/place/photo.html index 99cb11f3..1f58ce04 100644 --- a/templates/client/place/photo.html +++ b/templates/client/place/photo.html @@ -4,7 +4,7 @@ {% block bread_scrumbs %}