diff --git a/.gitignore b/.gitignore index 1ded53a1..bd43984b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ .idea/ media/ media +logs/ Thumbs.db npm-debug.log /proj/local.py @@ -14,4 +15,4 @@ npm-debug.log -node_modules \ No newline at end of file +node_modules diff --git a/accounts/admin.py b/accounts/admin.py index d267f0d1..9457de21 100644 --- a/accounts/admin.py +++ b/accounts/admin.py @@ -13,14 +13,20 @@ from django.utils.translation import ugettext as _ from models import User from forms import UserForm, UserCreationForm, ChangePasswordForm, EmailAnnouncementForm, UserFilterForm #custom views -from functions.admin_views import AdminView, AdminListView from django.views.generic import UpdateView +from functions.admin_views import AdminView, AdminListView, paginate_results class UserListView(AdminListView): template_name = 'admin/accounts/user_list.html' form_class = UserFilterForm model = User + def get_context_data(self, **kwargs): + context = super(UserListView, self).get_context_data(**kwargs) + qs = self.model.objects.all() + result = paginate_results(qs, page=self.request.GET.get('page')) + context['object_list'] = result + return context class EditUser(UpdateView): model = User diff --git a/accounts/admin_urls.py b/accounts/admin_urls.py index 225255e1..66e92a22 100644 --- a/accounts/admin_urls.py +++ b/accounts/admin_urls.py @@ -3,10 +3,6 @@ from django.conf.urls import patterns, url from admin import UserListView, EditUser urlpatterns = patterns('', - #url(r'^registration/$', 'accounts.admin.registration'), - #url(r'^create_admin/$', 'accounts.admin.create_admin'), - #url(r'^create_md5user/$', 'accounts.admin.create_md5'), - # url(r'^change/(?P.*)/$', EditUser.as_view()), url(r'^change/(?P.*)/$', 'accounts.admin.user_change'), url(r'^all/$', UserListView.as_view()), url(r'^reset_password_email/$', 'accounts.admin.reset_password_email'), diff --git a/accounts/forms.py b/accounts/forms.py index 395ac037..2e9bc922 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -83,9 +83,7 @@ class UserForm(forms.ModelForm): company = forms.ChoiceField(label='Компания', choices=[(item.id, item.name) for item in Company.objects.language().all()], required=False) - organiser = forms.ChoiceField(label='Организатор', - choices=[(item.id, item.name) for item in Organiser.objects.language().all()], - required=False, initial=None) + title = forms.CharField(widget=forms.TextInput(attrs={'style': 'width: 550px'}), required=False) descriptions = forms.CharField(widget=forms.TextInput(attrs={'style': 'width: 550px'}), required=False) keywords = forms.CharField(widget=forms.TextInput(attrs={'style': 'width: 550px'}), required=False) @@ -105,9 +103,9 @@ class UserForm(forms.ModelForm): class Meta: model = User - exclude = ('username', 'email', 'last_login', 'password', 'is_admin', 'rating', 'is_superuser', 'is_staff' + exclude = ('organiser', 'username', 'email', 'last_login', 'password', 'is_admin', 'rating', 'is_superuser', 'is_staff' 'date_joined', - 'date_registered', 'date_modified') + 'date_registered', 'date_modified', 'is_active') def save(self, force_insert=False, force_update=False, commit=True): @@ -139,16 +137,16 @@ class UserForm(forms.ModelForm): profile.save() return user - def clean_url(self): - url = self.cleaned_data.get('url') - if url: - if User.objects.get(url=translit_with_separator(url)): - raise forms.ValidationError('Такой урл уже занят') - else: - return url - - def clean_organiser(self): - return clean_relation_field(self, 'organiser', Organiser) + #def clean_url(self): + # url = self.cleaned_data.get('url') + # if url: + # if User.objects.get(url=translit_with_separator(url)): + # raise forms.ValidationError('Такой урл уже занят') + # else: + # return url + + #def clean_organiser(self): + # return clean_relation_field(self, 'organiser', Organiser) def clean_company(self): return clean_relation_field(self, 'company', Company) diff --git a/accounts/models.py b/accounts/models.py index ce4e4b47..2c83a17b 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -144,6 +144,9 @@ class User(AbstractBaseUser, PermissionsMixin): class Meta: ordering=['-rating'] + def is_organiser(self): + return bool(self.organiser) + def get_full_name(self): """ Returns the first_name plus the last_name, with a space in between. diff --git a/company/views.py b/company/views.py index 80a04032..d82401a8 100644 --- a/company/views.py +++ b/company/views.py @@ -21,7 +21,7 @@ from meta.views import MetadataMixin class CompanySearchView(ListView): paginate_by = 10 - template_name = 'company/search.html' + template_name = 'client/company/search.html' search_form = CompanySearchForm model = Company diff --git a/core/admin_urls.py b/core/admin_urls.py index 81e844eb..bc8bb409 100644 --- a/core/admin_urls.py +++ b/core/admin_urls.py @@ -1,10 +1,10 @@ -from django.conf.urls import url, patterns -from views import NewPage, PageList, EditPage, DeletePage, PageDetailed - -urlpatterns = patterns('', - url(r'^new/$', NewPage.as_view(), name='new_page' ), - url(r'^all/$', PageList.as_view(), name = 'page_list'), - url(r'^edit/(?P.*)/$', EditPage.as_view(), name='edit_page'), - url(r'^delete/(?P.*)/$', DeletePage.as_view(), name='delete_page'), - url(r'^(?P.*)/$', PageDetailed.as_view(), name='page_view'), -) +from django.conf.urls import url, patterns +from views import NewPage, PageList, EditPage, DeletePage, PageDetailed + +urlpatterns = patterns('', + url(r'^new/$', NewPage.as_view(), name='new_page' ), + url(r'^all/$', PageList.as_view(), name = 'page_list'), + url(r'^edit/(?P.*)/$', EditPage.as_view(), name='edit_page'), + url(r'^delete/(?P.*)/$', DeletePage.as_view(), name='delete_page'), + url(r'^(?P.*)/$', PageDetailed.as_view(), name='page_view'), +) diff --git a/core/forms.py b/core/forms.py index 6244f97e..d00f080e 100644 --- a/core/forms.py +++ b/core/forms.py @@ -61,21 +61,12 @@ class PageForm(TranslatableModelForm): class Meta: model = Page - fields = ['url','title','h1','descriptions','keywords', 'body' ] + fields = ['url','title','h1','descriptions','keywords', 'body'] widgets = { 'body':CKEditorWidget, 'keywords':Textarea, 'descriptions':Textarea, } - def clean_url(self): - url = self.cleaned_data.get('url', None) - if url[0] == '/': - url = url[1:] - if url[-1] == '/': - url = url[:-1] - if ' ' in url: - url.replace(' ', '_') - return url diff --git a/core/models.py b/core/models.py index 268a7009..56d75875 100644 --- a/core/models.py +++ b/core/models.py @@ -4,7 +4,7 @@ from django.shortcuts import get_object_or_404 from django.db import models from exposition.models import Exposition -from settings.models import create_transl_fields +import copy from theme.models import Theme from country.models import Country from city.models import City @@ -114,24 +114,39 @@ class Page(TranslatableModel): def get_absolute_url(self): return reverse('page_view', args=[self.url]) + def __init__(self, *args, **kwargs): + super(Page, self).__init__(*args, **kwargs) + self.cache_fields = ['h1', 'body','title', 'description', 'keywords'] + self.var_cache = {var: copy.copy(getattr(self, var)) for var in self.cache_fields} + self.is_new = True + def save(self, *args, **kwargs): super(Page,self).save(*args, **kwargs) - - all_field_names = list(self._translated_field_names) - clear_f_n = [] - for field_name in all_field_names: - if field_name not in ['master', 'master_id',u'id', 'language_code']: - clear_f_n.append(field_name) - field_items = {field_name:getattr(self, field_name) for field_name in clear_f_n} - - langs = [lan[0] for lan in settings.LANGUAGES] - for lang in langs: - if lang not in self.get_available_languages(): - self.translate(lang) - for field in clear_f_n: - setattr(self, field, field_items.get(field, '')) - obj = super(Page,self).save(*args, **kwargs) - return obj + self.initial_language = 'ru' + + new_values = {field: getattr(self, field) for field in self.cache_fields} + langs = [code for code, _ in settings.LANGUAGES] + if self.is_new: + for lang in langs: + if lang not in self.get_available_languages(): + self.translate(lang) + for key, value in new_values.items(): + setattr(self, key, value) + self.save_translations(self) + else: + translations = {obj.language_code:obj for obj in list(self.translations.all())} + for lang in langs: + if lang is not self.initial_language: + tr = translations[lang] + for key, value in new_values.items(): + #if u'%s' % getattr(self, key) is u'' or getattr(self, key) is u'%s' % self.var_cache[key]: + setattr(tr, key, value) + tr.save() + + self.lazy_translation_getter(self.initial_language) + self.var_cache = {var: copy.copy(getattr(self, var)) for var in self.cache_fields} + self.is_new = False + return self def __unicode__(self): return self.url diff --git a/core/urls.py b/core/urls.py index 88f2e7c0..b449ce91 100644 --- a/core/urls.py +++ b/core/urls.py @@ -1,11 +1,11 @@ -from django.conf.urls import url, patterns -from models import LatestExpositions, CountryFeeds, CityFeeds, ThemeFeeds - - -urlpatterns = patterns('', - url(r'^latest/$', LatestExpositions()), - url(r'^country/(?P.*)/$', CountryFeeds()), - url(r'^city/(?P.*)/$', CityFeeds()), - url(r'^theme/(?P.*)/$', ThemeFeeds()), - -) +from django.conf.urls import url, patterns +from models import LatestExpositions, CountryFeeds, CityFeeds, ThemeFeeds + + +urlpatterns = patterns('', + url(r'^latest/$', LatestExpositions()), + url(r'^country/(?P.*)/$', CountryFeeds()), + url(r'^city/(?P.*)/$', CityFeeds()), + url(r'^theme/(?P.*)/$', ThemeFeeds()), + +) diff --git a/core/utils.py b/core/utils.py index ee429eee..37a7f4ce 100644 --- a/core/utils.py +++ b/core/utils.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- +""" +http://www.simplistix.co.uk/presentations/python-excel.pdf + +""" import xlwt import datetime - -from exposition.models import Exposition -from conference.models import Conference - from django.core.exceptions import ObjectDoesNotExist HEADER_STYLE = xlwt.easyxf('font: bold on') @@ -16,6 +16,7 @@ CELL_STYLE_MAP = ( (bool, xlwt.easyxf(num_format_str='BOOLEAN')), ) + def multi_getattr(obj, attr, default=None): attributes = attr.split(".") for i in attributes: @@ -42,33 +43,65 @@ def get_column_cell(obj, name): return ', '.join(unicode(x).strip() for x in attr.all()) return attr -def queryset_to_workbook(queryset, columns, header_style=None, default_style=None, cell_style_map=None): + +def queryset_to_workbook(queryset, columns, report_date = None): + + # defining styles for different types of cells + main_style = xlwt.Style.easyxf( + "font: name Calibri, height 600, bold False;" + "borders: left thin, right thin, top thin, bottom thin;" + "alignment: horizontal left, vertical center, indent 7;" + "pattern: pattern solid, fore_colour white;" + ) + + header_style = xlwt.Style.easyxf( + 'font: name Calibri, height 400, bold False;' + 'borders: left no_line, right no_line, top thin, bottom thin;' + 'alignment: horizontal center, shrink_to_fit True;' + 'pattern: pattern solid, fore_color gray_ega;', + ) + odd_style = xlwt.Style.easyxf( + 'font: name Calibri, height 300, bold False;' + 'borders: left thin, right thin, top thin, bottom thin;' + 'alignment: horizontal center, wrap True;' + 'pattern: pattern solid, fore_color white;', + ) + even_style = xlwt.Style.easyxf( + 'font: name Calibri, height 300, bold False;' + 'borders: left thin, right thin, top thin, bottom thin;' + 'alignment: horizontal center, wrap True;' + 'pattern: pattern solid, fore_color silver_ega;', + ) + # creating workbook and adding sheet workbook = xlwt.Workbook() - report_date = datetime.date.today() - sheet_name = 'Export {0}'.format(report_date.strftime('%Y-%m-%d')) + report_date = report_date or datetime.date.today() + sheet_name = u'My calendar {0}'.format(report_date.strftime('%Y-%B')) sheet = workbook.add_sheet(sheet_name) - if not header_style: - header_style = HEADER_STYLE - if not default_style: - default_style = DEFAULT_STYLE - if not cell_style_map: - cell_style_map = CELL_STYLE_MAP - - obj = queryset[0] - - for y, column in enumerate(columns): - header_list=[u'Название события',u'Страна',u'Город',u'Место проведения', u'Дата начала', u'Дата окончания'] - - sheet.write(0, y, header_list[y], header_style) - - for x, obj in enumerate(queryset, start=1): + # drawing head part with image + sheet.write_merge(0, 6, 0, 6, u'Мой календарь собитий на %s года' % report_date.strftime("%B %Y"), main_style) + for i in range(7): + sheet.row(i).set_style(xlwt.Style.easyxf('font:height 300;')) + sheet.insert_bitmap('/home/www/proj/media/logo.bmp', row=0, col=5, x=0, y=0, scale_x=0.3, scale_y=2) + + # drawing headers + header_list = [u'#', u'Название события',u'Даты',u'Краткое описание',u'Место проведения', u'Заметка', u'Ссылка на событие'] + for i, column in enumerate(columns): + sheet.write(8, i, header_list[i], header_style) + sheet.col(i).width = 8000 + sheet.col(0).width = 2000 + + # fill data + for x, obj in enumerate(queryset, start=9): for y, column in enumerate(columns): - value = get_column_cell(obj, column) - style = default_style - for value_type, cell_style in cell_style_map: - if isinstance(value, value_type): - style = cell_style + try: + value = getattr(obj, column) + except: + value = "-" + if x % 2 == 0: + style = even_style + else: + style = odd_style sheet.write(x, y, value, style) return workbook diff --git a/core/views.py b/core/views.py index 9e0af308..03e01142 100644 --- a/core/views.py +++ b/core/views.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -from django.shortcuts import render_to_response from country.models import Country from city.models import City from place_exposition.models import PlaceExposition @@ -218,11 +217,14 @@ class PageList(ListView): template_name = 'page_admin_list.html' model = Page order = 'created' -from django import forms + + from django.http import HttpResponseRedirect +import datetime + class EditPage(UpdateView): model = Page - template_name = 'new_page.html' + template_name = 'admin/page/new_page.html' form_class = PageForm slug_url_kwarg = 'url' slug_field = 'url' @@ -233,7 +235,8 @@ class EditPage(UpdateView): return context def get_success_url(self): - return HttpResponseRedirect('/admin/page/all/') + return reverse_lazy('page_list') + class DeletePage(DeleteView): template_name = 'admin/page/page_confirm_delete.html' @@ -244,39 +247,54 @@ class DeletePage(DeleteView): class PageDetailed(DetailView): model = Page - template_name = 'client/base_catalog.html' + template_name = 'admin/page/page_template_view.html' slug_field = 'url' slug_url_kwarg = 'url' - - - # ------------ XLS Export ---------------- from django.http import HttpResponse +from django.utils.translation import get_language from .utils import queryset_to_workbook from exposition.models import Exposition from conference.models import Conference +from django.core.urlresolvers import reverse + def download_workbook(request): - data = [(36539, 'expo'),(36602, 'expo'), (3033, 'conf'), (3053, 'conf')] + lang = get_language() + data = request.GET qs = [] - for obj in data: - if obj[1] == 'expo': - qs.append(Exposition.objects.get(id=obj[0])) - if obj[1] == 'conf': - qs.append(Conference.objects.get(id=obj[0])) + for i,obj in enumerate(data): + if data.get('data[%i][name]'%i) == 'expo': + qs.append(Exposition.objects.language(lang).get(id=data['data[%i][value]'%i])) + elif data.get('data[%i][name]'%i) == 'conf': + qs.append(Conference.objects.language(lang).get(id=data['data[%i][value]'%i])) + + earliest_event = qs[0].data_begin + for i, obj in enumerate(qs, start=1): + if obj.data_begin < earliest_event: + earliest_event = obj.data_begin + setattr(obj, 'number', i) + setattr(obj, 'dates', u'%s - %s'%(obj.data_begin.strftime('%d %B %Y'),obj.data_end.strftime('%d %B %Y'))) + setattr(obj, 'full_place', u'%s, %s, %s' % (obj.country, obj.city, getattr(obj.place, 'name', ''))) + try: + setattr(obj, 'link', u'http://www.expomap.ru%s)'%obj.get_absolute_url()) + except: + setattr(obj, 'link', u'http://www.expomap.ru%s)'%obj.get_permanent_url()) + columns = ( + 'number', 'name', - 'country.name', - 'city.name', - 'place.name', - 'data_begin', - 'data_end') + 'dates', + 'main_title', + 'full_place', + 'participation_note', + 'link') - workbook = queryset_to_workbook(qs, columns) + workbook = queryset_to_workbook(qs, columns, earliest_event) response = HttpResponse(content_type='application/vnd.ms-excel') - response['Content-Disposition'] = 'attachment; filename="export.xls"' + response['Content-Disposition'] = 'attachment; filename="My calendar.xls"' workbook.save(response) return response diff --git a/django_messages/locale/en/LC_MESSAGES/django.po b/django_messages/locale/en/LC_MESSAGES/django.po new file mode 100644 index 00000000..5831c0f2 --- /dev/null +++ b/django_messages/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,374 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-09-08 13:44+0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: django_messages/admin.py:21 +msgid "group" +msgstr "" + +#: django_messages/admin.py:22 +msgid "Creates the message optionally for all users or a group of users." +msgstr "" + +#: django_messages/admin.py:30 +msgid "All users" +msgstr "" + +#: django_messages/admin.py:48 django_messages/models.py:94 +msgid "Message" +msgstr "" + +#: django_messages/admin.py:55 +msgid "Date/time" +msgstr "" + +#: django_messages/apps.py:6 django_messages/models.py:95 +msgid "Messages" +msgstr "" + +#: django_messages/fields.py:56 +#, python-format +msgid "The following usernames are incorrect: %(users)s" +msgstr "" + +#: django_messages/forms.py:17 django_messages/forms.py:66 +#: django_messages/models.py:55 +#: django_messages/templates/django_messages/inbox.html:10 +#: django_messages/templates/django_messages/outbox.html:10 +#: django_messages/templates/django_messages/trash.html:10 +#: django_messages/templates/django_messages/view.html:8 +msgid "Subject" +msgstr "" + +#: django_messages/forms.py:18 django_messages/forms.py:46 +#: django_messages/forms.py:67 django_messages/models.py:56 +msgid "Body" +msgstr "" + +#: django_messages/forms.py:65 django_messages/models.py:58 +#: django_messages/templates/django_messages/outbox.html:10 +#: django_messages/templates/django_messages/view.html:14 +msgid "Recipient" +msgstr "" + +#: django_messages/management.py:9 +msgid "Message Received" +msgstr "" + +#: django_messages/management.py:9 +msgid "you have received a message" +msgstr "" + +#: django_messages/management.py:10 +msgid "Message Sent" +msgstr "" + +#: django_messages/management.py:10 +msgid "you have sent a message" +msgstr "" + +#: django_messages/management.py:11 +msgid "Message Replied" +msgstr "" + +#: django_messages/management.py:11 +msgid "you have replied to a message" +msgstr "" + +#: django_messages/management.py:12 +msgid "Reply Received" +msgstr "" + +#: django_messages/management.py:12 +msgid "you have received a reply to a message" +msgstr "" + +#: django_messages/management.py:13 +msgid "Message Deleted" +msgstr "" + +#: django_messages/management.py:13 +msgid "you have deleted a message" +msgstr "" + +#: django_messages/management.py:14 +msgid "Message Recovered" +msgstr "" + +#: django_messages/management.py:14 +msgid "you have undeleted a message" +msgstr "" + +#: django_messages/models.py:57 +#: django_messages/templates/django_messages/inbox.html:10 +#: django_messages/templates/django_messages/trash.html:10 +#: django_messages/templates/django_messages/view.html:10 +msgid "Sender" +msgstr "" + +#: django_messages/models.py:59 +msgid "Parent message" +msgstr "" + +#: django_messages/models.py:60 +msgid "sent at" +msgstr "" + +#: django_messages/models.py:61 +msgid "read at" +msgstr "" + +#: django_messages/models.py:62 +msgid "replied at" +msgstr "" + +#: django_messages/models.py:63 +msgid "Sender deleted at" +msgstr "" + +#: django_messages/models.py:64 +msgid "Recipient deleted at" +msgstr "" + +#: django_messages/templates/django_messages/base.html:9 +#: django_messages/templates/django_messages/inbox.html:6 +#: django_messages/templates/django_messages/new_message.html:13 +msgid "Inbox" +msgstr "" + +#: django_messages/templates/django_messages/base.html:10 +#: django_messages/templates/django_messages/outbox.html:6 +msgid "Sent Messages" +msgstr "" + +#: django_messages/templates/django_messages/base.html:11 +msgid "New Message" +msgstr "" + +#: django_messages/templates/django_messages/base.html:12 +msgid "Trash" +msgstr "" + +#: django_messages/templates/django_messages/compose.html:4 +msgid "Compose Message" +msgstr "" + +#: django_messages/templates/django_messages/compose.html:10 +msgid "Send" +msgstr "" + +#: django_messages/templates/django_messages/inbox.html:10 +msgid "Received" +msgstr "" + +#: django_messages/templates/django_messages/inbox.html:10 +#: django_messages/templates/django_messages/outbox.html:10 +#: django_messages/templates/django_messages/trash.html:10 +msgid "Action" +msgstr "" + +#: django_messages/templates/django_messages/inbox.html:22 +#: django_messages/templates/django_messages/outbox.html:19 +#: django_messages/templates/django_messages/trash.html:19 +#: django_messages/templates/django_messages/view.html:13 +msgid "DATETIME_FORMAT" +msgstr "" + +#: django_messages/templates/django_messages/inbox.html:23 +#: django_messages/templates/django_messages/outbox.html:20 +msgid "delete" +msgstr "" + +#: django_messages/templates/django_messages/inbox.html:29 +#: django_messages/templates/django_messages/outbox.html:26 +#: django_messages/templates/django_messages/trash.html:26 +msgid "No messages." +msgstr "" + +#: django_messages/templates/django_messages/new_message.html:4 +#, python-format +msgid "" +"Hello %(recipient)s,\n" +"\n" +"you received a private message from %(sender)s with\n" +"the following contents:" +msgstr "" + +#: django_messages/templates/django_messages/new_message.html:12 +#, python-format +msgid "Sent from %(site_url)s" +msgstr "" + +#: django_messages/templates/django_messages/new_message.html:14 +#: django_messages/templates/django_messages/view.html:20 +msgid "Reply" +msgstr "" + +#: django_messages/templates/django_messages/outbox.html:10 +msgid "Sent" +msgstr "" + +#: django_messages/templates/django_messages/trash.html:6 +msgid "Deleted Messages" +msgstr "" + +#: django_messages/templates/django_messages/trash.html:10 +#: django_messages/templates/django_messages/view.html:12 +msgid "Date" +msgstr "" + +#: django_messages/templates/django_messages/trash.html:20 +msgid "undelete" +msgstr "" + +#: django_messages/templates/django_messages/trash.html:29 +msgid "" +"Deleted Messages are removed from the trash at unregular intervals, don't " +"rely on this feature for long-time storage." +msgstr "" + +#: django_messages/templates/django_messages/view.html:6 +msgid "View Message" +msgstr "" + +#: django_messages/templates/django_messages/view.html:22 +msgid "Delete" +msgstr "" + +#: django_messages/templates/notification/messages_deleted/full.txt:1 +#, python-format +msgid "You have deleted the message '%(message)s'." +msgstr "" + +#: django_messages/templates/notification/messages_deleted/notice.html:1 +#, python-format +msgid "" +"You have deleted the message %(message)s." +msgstr "" + +#: django_messages/templates/notification/messages_received/full.txt:1 +#, python-format +msgid "" +"%(message_sender)s has sent you a message:\n" +"\n" +"%(message)s\n" +"\n" +"%(message_body)s\n" +"\n" +"http://%(current_site)s%(message_url)s" +msgstr "" + +#: django_messages/templates/notification/messages_received/notice.html:2 +#, python-format +msgid "" +"You have received the message %(message)s " +"from %(message_sender)s." +msgstr "" + +#: django_messages/templates/notification/messages_received/short.txt:1 +#: django_messages/templates/notification/messages_reply_received/short.txt:1 +#, python-format +msgid "%(notice)s by %(message_sender)s" +msgstr "" + +#: django_messages/templates/notification/messages_recovered/full.txt:1 +#, python-format +msgid "You have recovered the message '%(message)s'." +msgstr "" + +#: django_messages/templates/notification/messages_recovered/notice.html:1 +#, python-format +msgid "" +"You have recovered the message %(message)s." +msgstr "" + +#: django_messages/templates/notification/messages_replied/full.txt:1 +#, python-format +msgid "" +"You have replied to '%(message_parent_msg)s' from %(message_recipient)s." +msgstr "" + +#: django_messages/templates/notification/messages_replied/notice.html:2 +#, python-format +msgid "" +"You have replied to %(message_parent_msg)s " +"from %(message_recipient)s." +msgstr "" + +#: django_messages/templates/notification/messages_reply_received/full.txt:1 +#, python-format +msgid "" +"%(message_sender)s replied to '%(message_parent_msg)s':\n" +"\n" +"%(message)s\n" +"\n" +"%(message_body)s\n" +"\n" +"http://%(current_site)s%(message_url)s" +msgstr "" + +#: django_messages/templates/notification/messages_reply_received/notice.html:2 +#, python-format +msgid "%(message_sender)s has sent you a reply to %(message_parent_msg)s." +msgstr "" + +#: django_messages/templates/notification/messages_sent/full.txt:1 +#, python-format +msgid "You have sent the message '%(message)s' to %(message_recipient)s." +msgstr "" + +#: django_messages/templates/notification/messages_sent/notice.html:2 +#, python-format +msgid "" +"You have sent the message %(message)s to " +"%(message_recipient)s." +msgstr "" + +#: django_messages/utils.py:26 +#, python-format +msgid "" +"%(sender)s wrote:\n" +"%(body)s" +msgstr "" + +#: django_messages/utils.py:54 +#, python-format +msgid "Re%(prefix)s: %(subject)s" +msgstr "" + +#: django_messages/utils.py:60 +#, python-format +msgid "New Message: %(subject)s" +msgstr "" + +#: django_messages/views.py:78 django_messages/views.py:114 +msgid "Message successfully sent." +msgstr "" + +#: django_messages/views.py:121 +#, python-format +msgid "Re: %(subject)s" +msgstr "" + +#: django_messages/views.py:157 +msgid "Message successfully deleted." +msgstr "" + +#: django_messages/views.py:184 +msgid "Message successfully recovered." +msgstr "" diff --git a/expobanner/admin.py b/expobanner/admin.py index cfcaa599..0fe5c1bc 100644 --- a/expobanner/admin.py +++ b/expobanner/admin.py @@ -3,6 +3,7 @@ from django.views.generic import TemplateView, CreateView, ListView, UpdateView, from django.conf import settings from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404 +from django.db.models import Sum from expobanner.models import URL, BannerGroup, Banner, Paid, MainPage, Top from expobanner.forms import UrlCreateForm, BannerCreateGroupForm, BannerCreateForm, BannerGroupUpdateForm,\ PaidCreateForm, PaidUpdateForm, TopCreateForm, BannerLinkCreateForm, MainCreateForm, MainUpdateForm, TopUpdateForm @@ -32,6 +33,7 @@ class CreateBanner(AbstractCreate): model = Banner form_class = BannerCreateForm + class CreateLink(AbstractCreate): model = Banner form_class = BannerLinkCreateForm @@ -67,6 +69,7 @@ class BannerList(AbstractList): qs = qs.filter(group__isnull=False) return qs + class LinkList(AbstractList): model = Banner verbose = u'Список ссылок' @@ -114,7 +117,10 @@ class PaidList(ListView): paginate_by = settings.ADMIN_PAGINATION def get_queryset(self): - return self.model.objects.language().filter(paid_new__isnull=False) + qs = self.model.objects.language().filter(paid_new__isnull=False).order_by('-paid_new__public') + if self.request.GET.get('onlypublic'): + qs = qs.filter(paid_new__public=True) + return qs class PaidCreate(CreateView): @@ -162,6 +168,18 @@ class PaidStat(DetailView): model = Paid template_name = 'admin/expobanner/paid_stat.html' + def get_context_data(self, **kwargs): + context = super(PaidStat, self).get_context_data(**kwargs) + obj = self.object + context['all'] = obj.paidstat_set.aggregate( + official=Sum('official_clicks'), + ticket=Sum('tickets_clicks'), + participation=Sum('participation_clicks'), + catalog=Sum('catalog_clicks') + ) + return context + + # ---------------------------------- class MainList(ListView): model = Exposition @@ -169,7 +187,10 @@ class MainList(ListView): paginate_by = settings.ADMIN_PAGINATION def get_queryset(self): - return self.model.objects.language().filter(main__isnull=False) + qs = self.model.objects.language().filter(main__isnull=False).order_by('-main__public') + if self.request.GET.get('onlypublic'): + qs = qs.filter(main__public=True) + return qs class MainCreate(CreateView): @@ -202,6 +223,7 @@ def main_turn(request, pk, status): return HttpResponseRedirect('/admin/expobanners/main/list/') + class MainStat(DetailView): model = MainPage template_name = 'admin/expobanner/main_stat.html' @@ -210,10 +232,16 @@ class MainStat(DetailView): context = super(MainStat, self).get_context_data(**kwargs) obj = self.object context['stats'] = obj.link.banner_stat.all() + context['all'] = obj.link.banner_stat.aggregate( + views=Sum('view'), + clicks=Sum('click'), + unique_clicks=Sum('unique_click'), + unique_views=Sum('unique_view') + ) return context # ------------------------------------ - +from datetime import date class TopList(ListView): model = Exposition @@ -221,7 +249,10 @@ class TopList(ListView): paginate_by = settings.ADMIN_PAGINATION def get_queryset(self): - return self.model.objects.language().filter(top__isnull=False) + qs = self.model.objects.language().filter(top__isnull=False).order_by('-top__fr') + if self.request.GET.get('onlypublic'): + qs = qs.filter(top__fr__lte=date.today(), top__to__gte=date.today()) + return qs class TopCreate(CreateView): @@ -241,4 +272,4 @@ class TopUpdate(UpdateView): context = super(TopUpdate, self).get_context_data(**kwargs) obj = self.object context['exposition'] = obj.get_event() - return context \ No newline at end of file + return context diff --git a/expobanner/forms.py b/expobanner/forms.py index 85f479ea..84d45965 100644 --- a/expobanner/forms.py +++ b/expobanner/forms.py @@ -267,4 +267,4 @@ class TopUpdateForm(forms.ModelForm): top.save() self.save_m2m() - return top + return top \ No newline at end of file diff --git a/expobanner/managers.py b/expobanner/managers.py index 51f988af..3c78cc31 100644 --- a/expobanner/managers.py +++ b/expobanner/managers.py @@ -1,79 +1,79 @@ -# -*- coding: utf-8 -* -from datetime import date -from random import choice, shuffle -from django.db import models -from django.db.models import Q -from django.core.cache import cache - - -class BiasedManager(models.Manager): - def by_time(self, **kwargs): - all = super(BiasedManager, self).get_query_set().filter(**kwargs) - result = [] - for i in all: - for j in range(i.often): - result.append(i) - return result - - def one(self, **kwargs): - return choice(self.by_time(**kwargs)) - - def by_often(self, **kwargs): - result = self.by_time(**kwargs) - shuffle(result) - return result - - def create_for_paid(self, expo, url, role): - try: - name = str(expo.name) - except UnicodeEncodeError, UnicodeDecodeError: - name = expo.url - - alt = u'%s_%s'%(name, role) - return self.create(alt=alt, url=url, paid=True) - -class BannerGroupCached(models.Manager): - def all(self): - key = 'banner_group_all' - result = cache.get(key) - if not result: - result = list(self.filter(public=True)) - cache.set(key, result, 90) - return result - - def group_banners(self): - key = 'banner_group_banners' - result = cache.get(key) - if not result: - groups = self.all() - today = date.today() - result = {} - for group in groups: - result[group.slug] = list(group.banners.prefetch_related('urls', 'theme', 'country')\ - .filter(public=True, fr__lte=today)\ - .filter(Q(to__gte=today) | Q(to__isnull=True))) - cache.set(key, result, 70) - - return result - - -class URLCached(models.Manager): - def all(self): - key = 'banner_url_all' - result = cache.get(key) - if not result: - result = list(self.filter(public=True)) - cache.set(key, result, 150) - return result - -class TopCached(models.Manager): - def all(self): - key = 'expo_b_top_all' - result = cache.get(key) - if not result: - today = date.today() - result = list(self.prefetch_related('theme', 'country', 'excluded_tags', 'excluded_cities'). - filter(fr__lte=today).filter(Q(to__gte=today) | Q(to__isnull=True))) - cache.set(key, result, 80) - +# -*- coding: utf-8 -* +from datetime import date +from random import choice, shuffle +from django.db import models +from django.db.models import Q +from django.core.cache import cache + + +class BiasedManager(models.Manager): + def by_time(self, **kwargs): + all = super(BiasedManager, self).get_query_set().filter(**kwargs) + result = [] + for i in all: + for j in range(i.often): + result.append(i) + return result + + def one(self, **kwargs): + return choice(self.by_time(**kwargs)) + + def by_often(self, **kwargs): + result = self.by_time(**kwargs) + shuffle(result) + return result + + def create_for_paid(self, expo, url, role): + try: + name = str(expo.name) + except UnicodeEncodeError, UnicodeDecodeError: + name = expo.url + + alt = u'%s_%s'%(name, role) + return self.create(alt=alt, url=url, paid=True) + +class BannerGroupCached(models.Manager): + def all(self): + key = 'banner_group_all' + result = cache.get(key) + if not result: + result = list(self.filter(public=True)) + cache.set(key, result, 90) + return result + + def group_banners(self): + key = 'banner_group_banners' + result = cache.get(key) + if not result: + groups = self.all() + today = date.today() + result = {} + for group in groups: + result[group.slug] = list(group.banners.prefetch_related('urls', 'theme', 'country')\ + .filter(public=True, fr__lte=today)\ + .filter(Q(to__gte=today) | Q(to__isnull=True))) + cache.set(key, result, 70) + + return result + + +class URLCached(models.Manager): + def all(self): + key = 'banner_url_all' + result = cache.get(key) + if not result: + result = list(self.filter(public=True)) + cache.set(key, result, 150) + return result + +class TopCached(models.Manager): + def all(self): + key = 'expo_b_top_all' + result = cache.get(key) + if not result: + today = date.today() + result = list(self.prefetch_related('theme', 'country', 'excluded_tags', 'excluded_cities'). + filter(fr__lte=today).filter(Q(to__gte=today) | Q(to__isnull=True))) + cache.set(key, result, 80) + return result \ No newline at end of file diff --git a/expobanner/models.py b/expobanner/models.py index 7091af0e..2208fc9a 100644 --- a/expobanner/models.py +++ b/expobanner/models.py @@ -1,323 +1,328 @@ -# -*- coding: utf-8 -*- -import random -import hashlib -from datetime import datetime, date -from django.db import models -from django.utils.translation import ugettext_lazy as _ -from django.conf import settings -from django.contrib.sites.models import Site -from django.db.models.signals import post_save -from .managers import BiasedManager, BannerGroupCached, URLCached, TopCached -from .mixins import StatMixin -from theme.models import Theme -from country.models import Country - - -class URL(models.Model): - title = models.CharField(verbose_name=u'Заголовок', max_length=256) - url = models.CharField(verbose_name=u'URL or URL RegEx', max_length=2048) - regex = models.BooleanField(verbose_name=u'RegEx', default=False) - sites = models.ManyToManyField(Site, related_name='site_urls', verbose_name=_('Sites'), null=True, blank=True) - - public = models.BooleanField(verbose_name=u'Активный', default=True) - created_at = models.DateTimeField(verbose_name=_('Created At'), auto_now_add=True) - updated_at = models.DateTimeField(verbose_name=_('Updated At'), auto_now=True) - - objects = models.Manager() - cached = URLCached() - - def __unicode__(self): - return self.title - - class Meta: - ordering = ['-created_at'] - verbose_name = _('URL') - verbose_name_plural = _('URLs') - - def get_admin_url(self): - return '/admin/expobanners/banners/url/%d/edit/'%self.id - - -class BannerGroup (models.Model): - name = models.CharField(verbose_name=u'Имя', max_length=255) - slug = models.SlugField(verbose_name=u'URL', unique=True) - width = models.PositiveSmallIntegerField(verbose_name=u'Ширина', default=0) - height = models.PositiveSmallIntegerField(verbose_name=u'Высота', default=0) - speed = models.PositiveSmallIntegerField(verbose_name=u'Скорость отображения', default=2000) - - public = models.BooleanField(verbose_name=u'Активная', default=True) - created_at = models.DateTimeField(verbose_name=_('Created At'), auto_now_add=True) - updated_at = models.DateTimeField(verbose_name=_('Updated At'), auto_now=True) - - objects = models.Manager() - cached = BannerGroupCached() - - def size(self): - return '%sx%s' % (self.width, self.height) - - def __unicode__(self): - return '%s - [%s x %s]' % (self.name, self.width, self.height) - - class Meta: - ordering = ['name'] - verbose_name = _('Banner Group') - verbose_name_plural = _('Banner Groups') - - def get_admin_url(self): - return '/admin/expobanners/banners/group/%d/edit/'%self.id - - -class Banner(models.Model, StatMixin): - objects = BiasedManager() - - title = models.CharField(verbose_name=u'Заголовок', max_length=255, blank=True) - alt = models.CharField(verbose_name=_('Alt'), max_length=255) - - text = models.TextField(verbose_name=u'Текст', blank=True, null=True) - img = models.FileField(verbose_name=u'Картинка', upload_to='expo_upload', blank=True, null=True) - url = models.CharField(verbose_name=u'URL', max_length=1024) - fr = models.DateField(default=date.today()) - to = models.DateField(blank=True, null=True) - - theme = models.ManyToManyField(Theme, blank=True, null=True, verbose_name=u'Тематика') - country = models.ManyToManyField(Country, blank=True, null=True, verbose_name=u'Страна') - - sort = models.PositiveSmallIntegerField(verbose_name=u'Сорт', default=500) - - group = models.ForeignKey(BannerGroup, related_name='banners', verbose_name=u'Место', null=True, blank=True) - often = models.PositiveSmallIntegerField( - verbose_name=_('Often'), - help_text=_('A ten will display 10 times more often that a one.'), - choices=[[i, i] for i in range(11)], - default=1 - ) - urls = models.ManyToManyField(URL, related_name='url_banners', verbose_name=_('URLs'), null=True, blank=True) - - html = models.BooleanField(verbose_name=_('HTML?'), default=False) - flash = models.BooleanField(verbose_name=_('Flash?'), default=False) - popup = models.BooleanField(verbose_name=_('Popup?'), default=False) - paid = models.BooleanField(verbose_name=_('Is Paid event link?'), default=False) - link = models.BooleanField(verbose_name=_('Is simple link?'), default=False) - # for detecting popups - cookie = models.CharField(max_length=30, blank=True, null=True, default=settings.DEFAULT_POPUP_COOKIE) - - public = models.BooleanField(verbose_name=u'Активный', default=True) - created_at = models.DateTimeField(verbose_name=_('Created At'), auto_now_add=True) - updated_at = models.DateTimeField(verbose_name=_('Updated At'), auto_now=True) - - stat_pswd = models.CharField(max_length=16) - - class Meta: - ordering = ['-public'] - - def get_admin_url(self): - return '/admin/expobanners/banners/banner/%d/edit/'%self.id - - - def key(slef): - if hasattr(settings, 'SECRET_KEY'): - key = str(datetime.now()) + settings.SECRET_KEY - else: - key = str(datetime.now()) - return hashlib.md5(key).hexdigest() - - def log(self, request, type): - log = { - 'type': type, - 'banner': self, - 'group': self.group, - 'ip': request.META.get('REMOTE_ADDR'), - 'user_agent': request.META.get('HTTP_USER_AGENT'), - 'page': request.META.get('HTTP_REFERER'), - } - - if request.user.is_authenticated(): - log['user'] = request.user - return Log.objects.create(**log) - - @models.permalink - def image(self): - return ('banner_view', (), {'banner_id': self.pk, 'key': self.key()}) - - def impressions(self): - return Log.objects.filter(banner=self.pk, type=0).count() - - def views(self): - return Log.objects.filter(banner=self.pk, type=1).count() - - def clicks(self): - return Log.objects.filter(banner=self.pk, type=2).count() - - def __unicode__(self): - return self.title or self.alt - - def get_absolute_url(self): - if self.url == '#': - return self.url - else: - @models.permalink - def get_absolute_url(self): - return ('banner_click', (), {'banner_id': self.pk, 'key': self.key()}) - return get_absolute_url(self) - - def get_click_link(self): - return '/expo-b/click/%d/'%self.id - - class Meta: - ordering = ['sort'] - verbose_name = _('Banner') - verbose_name_plural = _('Banners') - - -class Log(models.Model): - banner = models.ForeignKey(Banner, related_name='banner_logs') - group = models.ForeignKey(BannerGroup, related_name='group_logs', verbose_name=_('Group'), blank=True, null=True) - urls = models.ManyToManyField(URL, related_name='url_logs', verbose_name=_('URLs'), blank=True) - - user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, related_name='users', verbose_name=_('User')) - datetime = models.DateTimeField(verbose_name=_('Clicked At'), auto_now_add=True) - ip = models.IPAddressField(verbose_name=_('IP'), null=True, blank=True) - user_agent = models.CharField(verbose_name=_('User Agent'), max_length=1024, null=True, blank=True) - page = models.URLField(verbose_name=_('Page'), null=True, blank=True) - key = models.CharField(verbose_name=_('User Agent'), max_length=32, null=True, blank=True) - TYPE_CHOICES = ( - (0, 'impressions'), - (1, 'view'), - (2, 'click') - ) - - type = models.PositiveSmallIntegerField(verbose_name=_('Type'), max_length=1, default=0, choices=TYPE_CHOICES) - - def __unicode__(self): - return '%s - (%s)' % (self.banner, self.datetime) - - -class LogStat(models.Model): - banner = models.ForeignKey(Banner, related_name='banner_stat', verbose_name=_('Banner'), blank=True) - group = models.ForeignKey(BannerGroup, related_name='group_stat', verbose_name=_('Group'), blank=True, null=True) - urls = models.ManyToManyField(URL, related_name='url_bloks', verbose_name=_('URLs'), null=True, blank=True) - - date = models.DateField(verbose_name=_('Data')) - view = models.PositiveIntegerField(verbose_name=_('Views')) - click = models.PositiveIntegerField(verbose_name=_('Clicks')) - unique_click = models.PositiveIntegerField(verbose_name=_('Unique Views'), blank=True, null=True) - unique_view = models.PositiveIntegerField(verbose_name=_('Unique Clicks')) - - def __unicode__(self): - return '%s - (%s)' % (self.banner, self.date) - - -# ------------------ -class Paid(models.Model, StatMixin): - tickets = models.ForeignKey(Banner, related_name='paid_tickets') - participation = models.ForeignKey(Banner, related_name='paid_participation') - official = models.ForeignKey(Banner, related_name='paid_official') - catalog = models.ForeignKey(Banner, related_name='paid_catalog') - logo = models.ImageField(upload_to='expo-b/paid', blank=True) - organiser = models.CharField(max_length=100, blank=True) - public = models.BooleanField(default=True, verbose_name=u'Активная') - stat_pswd = models.CharField(max_length=16) - created = models.DateTimeField(auto_now_add=True) - modified = models.DateTimeField(auto_now=True) - - class Meta: - ordering = ['-public'] - - def get_event(self): - try: - return self.exposition_set.all()[0] - except IndexError: - return None - - -class PaidStat(models.Model): - paid = models.ForeignKey(Paid) - date = models.DateField(verbose_name=_('Date')) - page_views = models.PositiveIntegerField(default=0) - price_views = models.PositiveIntegerField(default=0) - catalog_views = models.PositiveIntegerField(default=0) - catalog_clicks = models.PositiveIntegerField(default=0) - tickets_clicks = models.PositiveIntegerField(default=0) - participation_clicks = models.PositiveIntegerField(default=0) - official_clicks = models.PositiveIntegerField(default=0) - - -class Top(models.Model, StatMixin): - link = models.ForeignKey(Banner) - catalog = models.CharField(max_length=16, verbose_name=u'Каталог для топа') - position = models.PositiveIntegerField(blank=True, default=2, null=True, verbose_name=u'Позиция') - theme = models.ManyToManyField('theme.Theme', blank=True, null=True, verbose_name=u'Тематики') - excluded_tags = models.ManyToManyField('theme.Tag', blank=True, null=True, verbose_name=u'Исключить теги') - country = models.ManyToManyField('country.Country', blank=True, null=True, verbose_name=u'Страны') - excluded_cities = models.ManyToManyField('city.City', blank=True, null=True, verbose_name=u'Исключить города') - fr = models.DateField(default=date.today(), verbose_name=u'Начало') - to = models.DateField(blank=True, null=True, verbose_name=u'Конец') - stat_pswd = models.CharField(max_length=16) - - objects = models.Manager() - cached = TopCached() - - class Meta: - ordering = ['position'] - - def get_event(self): - try: - return self.exposition_set.all()[0] - except IndexError: - return None - -class TopStat(models.Model): - date = models.DateField() - theme = models.ForeignKey('theme.Theme', blank=True, null=True) - tag = models.ForeignKey('theme.Tag', blank=True, null=True) - country = models.ForeignKey('country.Country', blank=True, null=True) - city = models.ForeignKey('city.City', blank=True, null=True) - views = models.PositiveIntegerField(default=0) - clicks = models.PositiveIntegerField(default=0) - - -class MainPage(models.Model, StatMixin): - link = models.ForeignKey(Banner) - position = models.PositiveIntegerField(blank=True, default=2, null=True, verbose_name=u'Позиция') - public = models.BooleanField(default=True, verbose_name=u'Активная') - stat_pswd = models.CharField(max_length=16) - created = models.DateTimeField(auto_now_add=True) - modified = models.DateTimeField(auto_now=True) - - class Meta: - ordering = ['-public'] - - def get_event(self): - try: - return self.exposition_set.all()[0] - except IndexError: - return None - - -def generatePassword(length=5): - """ - generate random password - """ - SYMBOLS = [',', '.', '?', '!', '-', '+', '1', '2', '3', '4', '5', '6', '7', '8', - '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', - 'm', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', - 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '#'] - PASSWORD_LENGTH = length - newPassword = [] - for i in range(PASSWORD_LENGTH): - newPassword.append(SYMBOLS[random.randrange(0, len(SYMBOLS))]) - return ''.join(newPassword) - - -def generate_stat_pass(sender, **kwargs): - obj = kwargs['instance'] - if not obj.stat_pswd: - obj.stat_pswd = generatePassword() - obj.save() - - - -post_save.connect(generate_stat_pass, sender=Banner) -post_save.connect(generate_stat_pass, sender=Paid) -post_save.connect(generate_stat_pass, sender=Top) +# -*- coding: utf-8 -*- +import random +import hashlib +from datetime import datetime, date +from django.db import models +from django.utils.translation import ugettext_lazy as _ +from django.conf import settings +from django.contrib.sites.models import Site +from django.db.models.signals import post_save +from .managers import BiasedManager, BannerGroupCached, URLCached, TopCached +from .mixins import StatMixin +from theme.models import Theme +from country.models import Country + + +class URL(models.Model): + title = models.CharField(verbose_name=u'Заголовок', max_length=256) + url = models.CharField(verbose_name=u'URL or URL RegEx', max_length=2048) + regex = models.BooleanField(verbose_name=u'RegEx', default=False) + sites = models.ManyToManyField(Site, related_name='site_urls', verbose_name=_('Sites'), null=True, blank=True) + + public = models.BooleanField(verbose_name=u'Активный', default=True) + created_at = models.DateTimeField(verbose_name=_('Created At'), auto_now_add=True) + updated_at = models.DateTimeField(verbose_name=_('Updated At'), auto_now=True) + + objects = models.Manager() + cached = URLCached() + + def __unicode__(self): + return self.title + + class Meta: + ordering = ['-created_at'] + verbose_name = _('URL') + verbose_name_plural = _('URLs') + + def get_admin_url(self): + return '/admin/expobanners/banners/url/%d/edit/'%self.id + + +class BannerGroup (models.Model): + name = models.CharField(verbose_name=u'Имя', max_length=255) + slug = models.SlugField(verbose_name=u'URL', unique=True) + width = models.PositiveSmallIntegerField(verbose_name=u'Ширина', default=0) + height = models.PositiveSmallIntegerField(verbose_name=u'Высота', default=0) + speed = models.PositiveSmallIntegerField(verbose_name=u'Скорость отображения', default=2000) + + public = models.BooleanField(verbose_name=u'Активная', default=True) + created_at = models.DateTimeField(verbose_name=_('Created At'), auto_now_add=True) + updated_at = models.DateTimeField(verbose_name=_('Updated At'), auto_now=True) + + objects = models.Manager() + cached = BannerGroupCached() + + def size(self): + return '%sx%s' % (self.width, self.height) + + def __unicode__(self): + return '%s - [%s x %s]' % (self.name, self.width, self.height) + + class Meta: + ordering = ['name'] + verbose_name = _('Banner Group') + verbose_name_plural = _('Banner Groups') + + def get_admin_url(self): + return '/admin/expobanners/banners/group/%d/edit/'%self.id + + +class Banner(models.Model, StatMixin): + objects = BiasedManager() + + title = models.CharField(verbose_name=u'Заголовок', max_length=255, blank=True) + alt = models.CharField(verbose_name=_('Alt'), max_length=255) + + text = models.TextField(verbose_name=u'Текст', blank=True, null=True) + img = models.FileField(verbose_name=u'Картинка', upload_to='expo_upload', blank=True, null=True) + url = models.CharField(verbose_name=u'URL', max_length=1024) + fr = models.DateField(default=date.today()) + to = models.DateField(blank=True, null=True) + + theme = models.ManyToManyField(Theme, blank=True, null=True, verbose_name=u'Тематика') + country = models.ManyToManyField(Country, blank=True, null=True, verbose_name=u'Страна') + + sort = models.PositiveSmallIntegerField(verbose_name=u'Сорт', default=500) + + group = models.ForeignKey(BannerGroup, related_name='banners', verbose_name=u'Место', null=True, blank=True) + often = models.PositiveSmallIntegerField( + verbose_name=_('Often'), + help_text=_('A ten will display 10 times more often that a one.'), + choices=[[i, i] for i in range(11)], + default=1 + ) + urls = models.ManyToManyField(URL, related_name='url_banners', verbose_name=_('URLs'), null=True, blank=True) + + html = models.BooleanField(verbose_name=_('HTML?'), default=False) + flash = models.BooleanField(verbose_name=_('Flash?'), default=False) + popup = models.BooleanField(verbose_name=_('Popup?'), default=False) + paid = models.BooleanField(verbose_name=_('Is Paid event link?'), default=False) + link = models.BooleanField(verbose_name=_('Is simple link?'), default=False) + # for detecting popups + cookie = models.CharField(max_length=30, blank=True, null=True, default=settings.DEFAULT_POPUP_COOKIE) + + public = models.BooleanField(verbose_name=u'Активный', default=True) + created_at = models.DateTimeField(verbose_name=_('Created At'), auto_now_add=True) + updated_at = models.DateTimeField(verbose_name=_('Updated At'), auto_now=True) + + stat_pswd = models.CharField(max_length=16) + + class Meta: + ordering = ['-public'] + + def get_admin_url(self): + return '/admin/expobanners/banners/banner/%d/edit/'%self.id + + def key(slef): + if hasattr(settings, 'SECRET_KEY'): + key = str(datetime.now()) + settings.SECRET_KEY + else: + key = str(datetime.now()) + return hashlib.md5(key).hexdigest() + + def log(self, request, type): + log = { + 'type': type, + 'banner': self, + 'group': self.group, + 'ip': request.META.get('REMOTE_ADDR'), + 'user_agent': request.META.get('HTTP_USER_AGENT'), + 'page': request.META.get('HTTP_REFERER'), + } + + if request.user.is_authenticated(): + log['user'] = request.user + return Log.objects.create(**log) + + @models.permalink + def image(self): + return ('banner_view', (), {'banner_id': self.pk, 'key': self.key()}) + + def impressions(self): + return Log.objects.filter(banner=self.pk, type=0).count() + + def views(self): + return Log.objects.filter(banner=self.pk, type=1).count() + + def clicks(self): + return Log.objects.filter(banner=self.pk, type=2).count() + + def __unicode__(self): + return self.title or self.alt + + def get_absolute_url(self): + if self.url == '#': + return self.url + else: + @models.permalink + def get_absolute_url(self): + return ('banner_click', (), {'banner_id': self.pk, 'key': self.key()}) + return get_absolute_url(self) + + def get_click_link(self): + return '/expo-b/click/%d/'%self.id + + class Meta: + ordering = ['sort'] + verbose_name = _('Banner') + verbose_name_plural = _('Banners') + + +class Log(models.Model): + banner = models.ForeignKey(Banner, related_name='banner_logs') + group = models.ForeignKey(BannerGroup, related_name='group_logs', verbose_name=_('Group'), blank=True, null=True) + urls = models.ManyToManyField(URL, related_name='url_logs', verbose_name=_('URLs'), blank=True) + + user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, related_name='users', verbose_name=_('User')) + datetime = models.DateTimeField(verbose_name=_('Clicked At'), auto_now_add=True) + ip = models.IPAddressField(verbose_name=_('IP'), null=True, blank=True) + user_agent = models.CharField(verbose_name=_('User Agent'), max_length=1024, null=True, blank=True) + page = models.URLField(verbose_name=_('Page'), null=True, blank=True) + key = models.CharField(verbose_name=_('User Agent'), max_length=32, null=True, blank=True) + TYPE_CHOICES = ( + (0, 'impressions'), + (1, 'view'), + (2, 'click') + ) + + type = models.PositiveSmallIntegerField(verbose_name=_('Type'), max_length=1, default=0, choices=TYPE_CHOICES) + + def __unicode__(self): + return '%s - (%s)' % (self.banner, self.datetime) + + +class LogStat(models.Model): + banner = models.ForeignKey(Banner, related_name='banner_stat', verbose_name=_('Banner'), blank=True) + group = models.ForeignKey(BannerGroup, related_name='group_stat', verbose_name=_('Group'), blank=True, null=True) + urls = models.ManyToManyField(URL, related_name='url_bloks', verbose_name=_('URLs'), null=True, blank=True) + + date = models.DateField(verbose_name=_('Data')) + view = models.PositiveIntegerField(verbose_name=_('Views')) + click = models.PositiveIntegerField(verbose_name=_('Clicks')) + unique_click = models.PositiveIntegerField(verbose_name=_('Unique Views'), blank=True, null=True) + unique_view = models.PositiveIntegerField(verbose_name=_('Unique Clicks')) + + def __unicode__(self): + return '%s - (%s)' % (self.banner, self.date) + + class Meta: + ordering = ['-date'] + + +# ------------------ +class Paid(models.Model, StatMixin): + tickets = models.ForeignKey(Banner, related_name='paid_tickets') + participation = models.ForeignKey(Banner, related_name='paid_participation') + official = models.ForeignKey(Banner, related_name='paid_official') + catalog = models.ForeignKey(Banner, related_name='paid_catalog') + logo = models.ImageField(upload_to='expo-b/paid', blank=True) + organiser = models.CharField(max_length=100, blank=True) + public = models.BooleanField(default=True, verbose_name=u'Активная') + stat_pswd = models.CharField(max_length=16) + created = models.DateTimeField(auto_now_add=True) + modified = models.DateTimeField(auto_now=True) + + class Meta: + ordering = ['-public'] + + def get_event(self): + try: + return self.exposition_set.all()[0] + except IndexError: + return None + + +class PaidStat(models.Model): + paid = models.ForeignKey(Paid) + date = models.DateField(verbose_name=_('Date')) + page_views = models.PositiveIntegerField(default=0) + price_views = models.PositiveIntegerField(default=0) + catalog_views = models.PositiveIntegerField(default=0) + catalog_clicks = models.PositiveIntegerField(default=0) + tickets_clicks = models.PositiveIntegerField(default=0) + participation_clicks = models.PositiveIntegerField(default=0) + official_clicks = models.PositiveIntegerField(default=0) + + class Meta: + ordering = ['-date'] + + +class Top(models.Model, StatMixin): + link = models.ForeignKey(Banner) + catalog = models.CharField(max_length=16, verbose_name=u'Каталог для топа') + position = models.PositiveIntegerField(blank=True, default=2, null=True, verbose_name=u'Позиция') + theme = models.ManyToManyField('theme.Theme', blank=True, null=True, verbose_name=u'Тематики') + excluded_tags = models.ManyToManyField('theme.Tag', blank=True, null=True, verbose_name=u'Исключить теги') + country = models.ManyToManyField('country.Country', blank=True, null=True, verbose_name=u'Страны') + excluded_cities = models.ManyToManyField('city.City', blank=True, null=True, verbose_name=u'Исключить города') + fr = models.DateField(default=date.today(), verbose_name=u'Начало') + to = models.DateField(blank=True, null=True, verbose_name=u'Конец') + stat_pswd = models.CharField(max_length=16) + + objects = models.Manager() + cached = TopCached() + + class Meta: + ordering = ['position'] + + def get_event(self): + try: + return self.exposition_set.all()[0] + except IndexError: + return None + + +class TopStat(models.Model): + date = models.DateField() + theme = models.ForeignKey('theme.Theme', blank=True, null=True) + tag = models.ForeignKey('theme.Tag', blank=True, null=True) + country = models.ForeignKey('country.Country', blank=True, null=True) + city = models.ForeignKey('city.City', blank=True, null=True) + views = models.PositiveIntegerField(default=0) + clicks = models.PositiveIntegerField(default=0) + + +class MainPage(models.Model, StatMixin): + link = models.ForeignKey(Banner) + position = models.PositiveIntegerField(blank=True, default=2, null=True, verbose_name=u'Позиция') + public = models.BooleanField(default=True, verbose_name=u'Активная') + stat_pswd = models.CharField(max_length=16) + created = models.DateTimeField(auto_now_add=True) + modified = models.DateTimeField(auto_now=True) + + class Meta: + ordering = ['-public'] + + def get_event(self): + try: + return self.exposition_set.all()[0] + except IndexError: + return None + + +def generatePassword(length=5): + """ + generate random password + """ + SYMBOLS = [',', '.', '?', '!', '-', '+', '1', '2', '3', '4', '5', '6', '7', '8', + '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + 'm', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', + 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '#'] + PASSWORD_LENGTH = length + newPassword = [] + for i in range(PASSWORD_LENGTH): + newPassword.append(SYMBOLS[random.randrange(0, len(SYMBOLS))]) + return ''.join(newPassword) + + +def generate_stat_pass(sender, **kwargs): + obj = kwargs['instance'] + if not obj.stat_pswd: + obj.stat_pswd = generatePassword() + obj.save() + + +post_save.connect(generate_stat_pass, sender=Banner) +post_save.connect(generate_stat_pass, sender=Paid) +post_save.connect(generate_stat_pass, sender=Top) diff --git a/expobanner/templates/slider.html b/expobanner/templates/slider.html index fcd6bd12..e2dd73ac 100644 --- a/expobanner/templates/slider.html +++ b/expobanner/templates/slider.html @@ -1,74 +1,74 @@ -{% load thumbnail %} - -{% if banners %} - -
- - -
    - {% for banner in banners %} -
  • - {{ forloop.counter }} -
  • - {% endfor %} -
- - 〈   -   〉 - -
- - - - - +{% load thumbnail %} + +{% if banners %} + +
+ + +
    + {% for banner in banners %} +
  • + {{ forloop.counter }} +
  • + {% endfor %} +
+ + 〈   +   〉 + +
+ + + + + {% endif %} \ No newline at end of file diff --git a/expobanner/templatetags/banner.py b/expobanner/templatetags/banner.py index c1491a74..f7257f1c 100644 --- a/expobanner/templatetags/banner.py +++ b/expobanner/templatetags/banner.py @@ -1,74 +1,74 @@ -from ..models import Banner -from ..models import BannerGroup -from ..models import URL - -from django import template - -# For render tag -from django.template import Context -from django.template import Template - -import re - -register = template.Library() - - -@register.simple_tag(takes_context=True) -def banner_group(context, group, tpl='group.html'): - try: - page_url = context['request'].path_info - site = context['request'].site - group = BannerGroup.objects.get(slug=group) - good_urls = [] - for url in URL.objects.filter(public=True, sites__in=[site]): - if url.regex: - url_re = re.compile(url.url) - if url_re.findall(page_url): - good_urls.append(url) - elif page_url == url.url: - good_urls.append(url) - banners = Banner.objects.filter(public=True, group=group, urls__in=good_urls) - except: - banners = False - group = False - if(banners and group): - context['banners'] = banners - context['group'] = group - - t = template.loader.get_template(tpl) - return t.render(template.Context(context)) - - -@register.simple_tag(takes_context=True) -def banner_one(context, banner_id, tpl='banner.html'): - try: - page_url = context['request'].path_info - site = context['request'].site - good_urls = [] - for url in URL.objects.filter(public=True, sites__in=[site]): - if url.regex: - url_re = re.compile(url.url) - if url_re.findall(page_url): - good_urls.append(url) - elif page_url == url.url: - good_urls.append(url) - - banner = Banner.objects.get(id=banner_id, public=True, urls__in=good_urls) - except: - banner = False - - context['banner'] = banner - - t = template.loader.get_template(tpl) - return t.render(template.Context(context)) - - -# block render -@register.simple_tag(takes_context=True) -def render(context, content): - try: - tpl = Template(content) - content = Context(context) - return tpl.render(content) - except: - return 'Render Error' +from ..models import Banner +from ..models import BannerGroup +from ..models import URL + +from django import template + +# For render tag +from django.template import Context +from django.template import Template + +import re + +register = template.Library() + + +@register.simple_tag(takes_context=True) +def banner_group(context, group, tpl='group.html'): + try: + page_url = context['request'].path_info + site = context['request'].site + group = BannerGroup.objects.get(slug=group) + good_urls = [] + for url in URL.objects.filter(public=True, sites__in=[site]): + if url.regex: + url_re = re.compile(url.url) + if url_re.findall(page_url): + good_urls.append(url) + elif page_url == url.url: + good_urls.append(url) + banners = Banner.objects.filter(public=True, group=group, urls__in=good_urls) + except: + banners = False + group = False + if(banners and group): + context['banners'] = banners + context['group'] = group + + t = template.loader.get_template(tpl) + return t.render(template.Context(context)) + + +@register.simple_tag(takes_context=True) +def banner_one(context, banner_id, tpl='banner.html'): + try: + page_url = context['request'].path_info + site = context['request'].site + good_urls = [] + for url in URL.objects.filter(public=True, sites__in=[site]): + if url.regex: + url_re = re.compile(url.url) + if url_re.findall(page_url): + good_urls.append(url) + elif page_url == url.url: + good_urls.append(url) + + banner = Banner.objects.get(id=banner_id, public=True, urls__in=good_urls) + except: + banner = False + + context['banner'] = banner + + t = template.loader.get_template(tpl) + return t.render(template.Context(context)) + + +# block render +@register.simple_tag(takes_context=True) +def render(context, content): + try: + tpl = Template(content) + content = Context(context) + return tpl.render(content) + except: + return 'Render Error' diff --git a/expobanner/urls.py b/expobanner/urls.py index 189b2023..65e3a854 100644 --- a/expobanner/urls.py +++ b/expobanner/urls.py @@ -1,13 +1,13 @@ -from django.conf.urls import url -from expobanner.stat_views import * -from . import views - -urlpatterns = [ - url(r'^click/(?P\d{1,4})/$', views.click, name='banner_click'), - #url(r'^view/(?P\d+)/$', views.view, name='banner_view'), - # - url(r'^get-banners/$', views.get_banners), - url(r'^get-tops/$', views.get_top), - url(r'^banner/(?P\d+)/stat/$', BannerStat.as_view(), name='banner_stat_client'), - url(r'^paid/(?P\d+)/stat/$', PaidStat.as_view(), name='paid_stat_client'), -] +from django.conf.urls import url +from expobanner.stat_views import * +from . import views + +urlpatterns = [ + url(r'^click/(?P\d{1,4})/$', views.click, name='banner_click'), + #url(r'^view/(?P\d+)/$', views.view, name='banner_view'), + # + url(r'^get-banners/$', views.get_banners), + url(r'^get-tops/$', views.get_top), + url(r'^banner/(?P\d+)/stat/$', BannerStat.as_view(), name='banner_stat_client'), + url(r'^paid/(?P\d+)/stat/$', PaidStat.as_view(), name='paid_stat_client'), +] diff --git a/expobanner/views.py b/expobanner/views.py index 1b6f069b..a9517d05 100644 --- a/expobanner/views.py +++ b/expobanner/views.py @@ -1,100 +1,100 @@ -# -*- coding: utf-8 -*- -import json -import re -from django.http import HttpResponse -from django.shortcuts import redirect, get_object_or_404 -from django.shortcuts import render_to_response -from django.template import RequestContext -from .models import Banner, BannerGroup, URL, Top -from expobanner.utils import get_banner_by_params, get_client_ip, get_top_events, get_referer_view, set_cookie - - -def click(request, banner_id): - banner = get_object_or_404(Banner, pk=banner_id) - banner.log(request, 2) - return redirect(banner.url) - - -def view(request, banner_id): - banner = get_object_or_404(Banner, pk=banner_id) - banner.log(request, 1) - return redirect(banner.img.url) - -def get_banners(request): - url = get_referer_view(request, default='/') - # get urls by current url - urls = URL.cached.all() - good_urls = [] - for u in urls: - if u.regex: - try: - url_re = re.compile(u.url) - except: - continue - if url_re.findall(url): - good_urls.append(u) - elif url == u.url: - good_urls.append(u) - # fill parameters dict - params = {'theme': request.GET.getlist('theme', []), - 'tag': request.GET.get('tag'), - 'country': request.GET.get('country'), - 'city': request.GET.get('city'), - 'ip': get_client_ip(request)} - - group_banners = BannerGroup.cached.group_banners() - result = [] - cookie = None - # get banners for all groups - places = request.GET.getlist('places', []) - - for group, banners in group_banners.iteritems(): - if group not in places: - # on this page there is no such group - continue - banner = get_banner_by_params(banners, good_urls, params, request) - if banner: - if banner.html: - text = banner.text - img = '' - alt = '' - is_img = False - else: - text = '' - try: - img = banner.img.url - except ValueError: - continue - alt = banner.alt - is_img = True - result.append({'id': group, - 'url': banner.get_click_link(), - 'is_html': banner.html, - 'is_flash': banner.flash, - 'is_img': is_img, - 'is_popup': banner.popup, - 'img': img, - 'alt': alt, - 'text': text - }) - if banner.popup: - cookie = banner.cookie - # add view log - banner.log(request, 1) - response = HttpResponse(json.dumps(result, indent=4), content_type='application/json') - if cookie: - response = set_cookie(response, cookie, '1') - - return response - -def get_top(request): - params = {'theme': request.GET.getlist('theme', []), - 'tag': request.GET.get('tag'), - 'country': request.GET.get('country'), - 'city': request.GET.get('city'), - 'catalog': request.GET.get('catalog')} - - tops = Top.cached.all() - events = get_top_events(tops, params, request) - context = {'objects': events} +# -*- coding: utf-8 -*- +import json +import re +from django.http import HttpResponse +from django.shortcuts import redirect, get_object_or_404 +from django.shortcuts import render_to_response +from django.template import RequestContext +from .models import Banner, BannerGroup, URL, Top +from expobanner.utils import get_banner_by_params, get_client_ip, get_top_events, get_referer_view, set_cookie + + +def click(request, banner_id): + banner = get_object_or_404(Banner, pk=banner_id) + banner.log(request, 2) + return redirect(banner.url) + + +def view(request, banner_id): + banner = get_object_or_404(Banner, pk=banner_id) + banner.log(request, 1) + return redirect(banner.img.url) + +def get_banners(request): + url = get_referer_view(request, default='/') + # get urls by current url + urls = URL.cached.all() + good_urls = [] + for u in urls: + if u.regex: + try: + url_re = re.compile(u.url) + except: + continue + if url_re.findall(url): + good_urls.append(u) + elif url == u.url: + good_urls.append(u) + # fill parameters dict + params = {'theme': request.GET.getlist('theme', []), + 'tag': request.GET.get('tag'), + 'country': request.GET.get('country'), + 'city': request.GET.get('city'), + 'ip': get_client_ip(request)} + + group_banners = BannerGroup.cached.group_banners() + result = [] + cookie = None + # get banners for all groups + places = request.GET.getlist('places', []) + + for group, banners in group_banners.iteritems(): + if group not in places: + # on this page there is no such group + continue + banner = get_banner_by_params(banners, good_urls, params, request) + if banner: + if banner.html: + text = banner.text + img = '' + alt = '' + is_img = False + else: + text = '' + try: + img = banner.img.url + except ValueError: + continue + alt = banner.alt + is_img = True + result.append({'id': group, + 'url': banner.get_click_link(), + 'is_html': banner.html, + 'is_flash': banner.flash, + 'is_img': is_img, + 'is_popup': banner.popup, + 'img': img, + 'alt': alt, + 'text': text + }) + if banner.popup: + cookie = banner.cookie + # add view log + banner.log(request, 1) + response = HttpResponse(json.dumps(result, indent=4), content_type='application/json') + if cookie: + response = set_cookie(response, cookie, '1') + + return response + +def get_top(request): + params = {'theme': request.GET.getlist('theme', []), + 'tag': request.GET.get('tag'), + 'country': request.GET.get('country'), + 'city': request.GET.get('city'), + 'catalog': request.GET.get('catalog')} + + tops = Top.cached.all() + events = get_top_events(tops, params, request) + context = {'objects': events} return render_to_response('client/includes/exposition/expo_top.html', context, context_instance=RequestContext(request)) \ No newline at end of file diff --git a/exposition/forms.py b/exposition/forms.py index 5cb1380e..7036432a 100644 --- a/exposition/forms.py +++ b/exposition/forms.py @@ -217,7 +217,6 @@ class ExpositionCreateForm(forms.Form): exposition.country = Country.objects.get(id=data['country']) exposition.city = City.objects.get(id=data['city']) - if data.get('place'): exposition.place = PlaceExposition.objects.get(id=data['place']) else: @@ -359,7 +358,6 @@ class ExpositionCreateForm(forms.Form): price_catalog = cleaned_data.get('price_catalog').strip() return is_positive_integer(price_catalog) - def clean_visitors(self): """ checking visitors @@ -449,6 +447,12 @@ class ExpositionCreateForm(forms.Form): discount = cleaned_data.get('discount').strip() return is_positive_integer(discount) + + + + + + class ExpositionDeleteForm(forms.ModelForm): url = forms.CharField(widget=forms.HiddenInput()) diff --git a/exposition/models.py b/exposition/models.py index fbae6343..8a38e1a9 100644 --- a/exposition/models.py +++ b/exposition/models.py @@ -59,6 +59,8 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): data_end = models.DateField(verbose_name='Дата окончания') services = BitField(flags=flags) # relations + creator = models.ForeignKey('accounts.User', verbose_name=u'Создатель', on_delete=models.SET_NULL, + related_name='exposition_creator', blank=True, null=True) country = models.ForeignKey('country.Country', verbose_name='Страна', on_delete=models.PROTECT, related_name='exposition_country') city = models.ForeignKey('city.City', verbose_name='Город', on_delete=models.PROTECT, @@ -164,9 +166,6 @@ class Exposition(TranslatableModel, EventMixin, ExpoMixin): enable = ClientManager() imports = ExpoImportManager() - - - def __unicode__(self): return self.lazy_translation_getter('name', unicode(self.pk)) diff --git a/functions/admin_views.py b/functions/admin_views.py index 0fb38183..d20b361d 100644 --- a/functions/admin_views.py +++ b/functions/admin_views.py @@ -90,6 +90,7 @@ def paginate_results(qs, page=None): return result +from hvad.models import TranslatableModel class AdminListView(FormView): def get_form(self, form_class): @@ -126,7 +127,10 @@ class AdminListView(FormView): def get_context_data(self, **kwargs): context = super(AdminListView, self).get_context_data(**kwargs) - qs = self.model.objects.language().all().order_by('name') + if issubclass(self.model, TranslatableModel): + qs = self.model.objects.language('all').all().order_by('name') + else: + qs = self.model.objects.all().order_by('name') result = paginate_results(qs, page=self.request.GET.get('page')) context['object_list'] = result return context diff --git a/import_xls/excel_settings.py b/import_xls/excel_settings.py index 182c7482..936c5913 100644 --- a/import_xls/excel_settings.py +++ b/import_xls/excel_settings.py @@ -27,7 +27,7 @@ def get_theme(value): def get_tag(value): - tag_names = [item['name'] for item in value.all().values('name')] + tag_names = [item['name'] for item in value.language('ru').all().values('name')] return ','.join(tag_names) def get_place_type(value): diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po index 5141fd62..301efef5 100644 Binary files a/locale/en/LC_MESSAGES/django.po and b/locale/en/LC_MESSAGES/django.po differ diff --git a/meta/admin.py b/meta/admin.py index 5d944cd3..7f21eb6b 100644 --- a/meta/admin.py +++ b/meta/admin.py @@ -1,13 +1,7 @@ # -*- 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.http import HttpResponseRedirect 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 +# models and forms from models import MetaSetting from forms import MetaForm, MetaFilterForm from functions.admin_views import AdminListView, AdminView @@ -45,7 +39,7 @@ class MetaView(AdminView): data['keywords_%s' % code] = trans_obj.keywords data['h1_%s' % code] = trans_obj.h1 - form =form_class(initial=data) + form = form_class(initial=data) return form else: return form_class() diff --git a/meta/admin_urls.py b/meta/admin_urls.py index a545ff76..f93ae2c7 100644 --- a/meta/admin_urls.py +++ b/meta/admin_urls.py @@ -1,16 +1,15 @@ # -*- coding: utf-8 -*- -from django.conf.urls import patterns, include, url -from admin import MetaListView, MetaView -from .views import CreateSeoText, SeoTextList, EditSeoText, DeleteSeoText +from django.conf.urls import patterns, url +from views import CreateSeoText, SeoTextList, EditSeoText, DeleteSeoText +from .admin import MetaListView, MetaView -urlpatterns = patterns('conference.admin', +urlpatterns = patterns('', url(r'^seo/new/$', CreateSeoText.as_view(), name='seo_new'), url(r'^seo/all/$', SeoTextList.as_view(), name='seo_all'), url(r'^seo/edit/(?P\d{1,5})/$', EditSeoText.as_view(), name='seo_edit'), url(r'^seo/delete/(?P\d{1,5})/$', DeleteSeoText.as_view(), name='seo_delete'), url(r'^all/$', MetaListView.as_view()), - #url(r'^change/(?P.*)/$', 'conference_change'), - url(r'^(?P.*)/$', MetaView.as_view()), + url(r'^(?P\d{1,6})/$', MetaView.as_view()), url(r'^$', MetaView.as_view()), ) \ No newline at end of file diff --git a/meta/forms.py b/meta/forms.py index eb93f28a..fd3c009a 100644 --- a/meta/forms.py +++ b/meta/forms.py @@ -1,9 +1,11 @@ # -*- coding: utf-8 -*- from django import forms from django.conf import settings -from models import MetaSetting +from models import MetaSetting, SeoText from functions.translate import fill_with_signal from functions.admin_forms import AdminFilterForm +from ckeditor.widgets import CKEditorWidget +from hvad.forms import TranslatableModelForm class MetaForm(forms.Form): @@ -14,7 +16,7 @@ class MetaForm(forms.Form): create dynamical translated fields fields """ super(MetaForm, self).__init__(*args, **kwargs) - #creates translated forms example: name_ru, name_en + # 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): @@ -44,17 +46,14 @@ class MetaForm(forms.Form): fill_with_signal(MetaSetting, meta, data) meta.save() + class MetaFilterForm(AdminFilterForm): model = MetaSetting -from .models import SeoText -from ckeditor.widgets import CKEditorWidget -from hvad.forms import TranslatableModelForm - class SeoTextForm(TranslatableModelForm): - + # lang = forms.ChoiceField(choices=settings.LANGUAGES) class Meta: model = SeoText - fields = ['url', 'title', 'body'] - widgets = {'body':CKEditorWidget} \ No newline at end of file + fields = ['url', 'title', 'page_title', 'description', 'body'] + widgets = {'body': CKEditorWidget} diff --git a/meta/models.py b/meta/models.py index 0bd6bdc0..98c6c5cd 100644 --- a/meta/models.py +++ b/meta/models.py @@ -3,9 +3,15 @@ from django.db import models from django.utils import translation from django.db.models.signals import post_save from django.utils.translation import ugettext_lazy as _ +from django.conf import settings +from django.core.urlresolvers import reverse_lazy +from django.core.cache import cache from hvad.models import TranslatableModel, TranslatedFields, TranslationManager from pymorphy.django_conf import default_morph as morph from functions.signal_handlers import post_save_handler +import copy + + # additional funcs MONTHES = {'jan': _(u'январе'), 'feb': _(u'феврале'), 'mar': _(u'марте'), 'apr': _(u'апреле'), @@ -118,62 +124,70 @@ post_save.connect(post_save_handler, sender=MetaSetting) # SEO - tests # -from django.db import models -from hvad.models import TranslatableModel, TranslatedFields -from django.conf import settings -from django.core.urlresolvers import reverse_lazy -from django.core.cache import cache - - class SeoTextManager(TranslationManager): cache_time = 120 + def cache_get(self, *args, **kwargs): url = kwargs.get('url') lang = kwargs.get('lang')[:2] or translation.get_language()[:2] key = 'seo_text_cache' result = cache.get(key) if result: - return result.get(lang+'_' + url) + return result.get("%s_%s" % (lang, url)) qs = list(SeoText.objects.language('all')) - value_dict = {obj.language_code+'_'+obj.url:obj for obj in qs} + value_dict = {obj.language_code+'_'+obj.url: obj for obj in qs} cache.set(key, value_dict, self.cache_time) - return value_dict.get(lang+'_'+url) - + return value_dict.get("%s_%s" % (lang, url)) class SeoText(TranslatableModel): - - url = models.CharField(max_length=50, unique=True) + url = models.CharField(max_length=50, unique=True, verbose_name=u"URL: www.expomap.ru") translations = TranslatedFields( - title=models.CharField(max_length=255), - body=models.TextField() + title=models.CharField(max_length=255, verbose_name=u"Заголовок"), + page_title=models.CharField(max_length=255, verbose_name=u"Тайтл страницы"), + description=models.CharField(max_length=1000, verbose_name=u"Дескрипшн"), + body=models.TextField(verbose_name=u"Текст") ) objects = SeoTextManager() + def __init__(self, *args, **kwargs): + super(SeoText, self).__init__(*args, **kwargs) + self.cache_fields = ['title', 'body', 'page_title', 'description'] + self.is_new = True + def get_absolute_url(self): - return reverse_lazy('seo_all') + return self.url def save(self, *args, **kwargs): - super(SeoText,self).save(*args, **kwargs) - - all_field_names = list(self._translated_field_names) - clear_f_n = [] - for field_name in all_field_names: - if field_name not in ['master', 'master_id', u'id', 'language_code']: - clear_f_n.append(field_name) - field_items = {field_name:getattr(self, field_name) for field_name in clear_f_n} - - langs = [lan[0] for lan in settings.LANGUAGES] - for lang in langs: - if lang not in self.get_available_languages(): - self.translate(lang) - for field in clear_f_n: - setattr(self, field, field_items.get(field, '')) - super(SeoText,self).save(*args, **kwargs) - return SeoText + super(SeoText, self).save(*args, **kwargs) + self.initial_language = 'ru' + + new_values = {field: getattr(self, field) for field in self.cache_fields} + langs = [code for code, _ in settings.LANGUAGES] + if self.is_new: + for lang in langs: + if lang not in self.get_available_languages(): + self.translate(lang) + for key, value in new_values.items(): + setattr(self, key, value) + self.save_translations(self) + else: + translations = {obj.language_code:obj for obj in list(self.translations.all())} + for lang in langs: + if lang is not self.initial_language: + tr = translations[lang] + for key, value in new_values.items(): + #if u'%s' % getattr(self, key) is u'' or getattr(self, key) is u'%s' % self.var_cache[key]: + setattr(tr, key, value) + tr.save() + + self.lazy_translation_getter(self.initial_language) + self.var_cache = {var: copy.copy(getattr(self, var)) for var in self.cache_fields} + self.is_new = False + return self def __unicode__(self): return self.url diff --git a/meta/views.py b/meta/views.py index 28d30eba..81db7390 100644 --- a/meta/views.py +++ b/meta/views.py @@ -1,9 +1,9 @@ from __future__ import unicode_literals - +from . import settings +from django.views.generic import CreateView, UpdateView, DeleteView, ListView from django.core.exceptions import ImproperlyConfigured from models import MetaSetting - -from . import settings +from .forms import SeoTextForm, SeoText class Meta(object): @@ -189,10 +189,6 @@ class MetadataMixin(object): return context -from django.views.generic import CreateView, UpdateView, DeleteView, ListView -from .models import SeoText -from .forms import SeoTextForm - class CreateSeoText(CreateView): form_class = SeoTextForm @@ -212,6 +208,7 @@ class EditSeoText(UpdateView): template_name = "admin/meta/create_seo_text.html" + class DeleteSeoText(DeleteView): model = SeoText template_name = "admin/meta/seo_confirm_delete.html" diff --git a/password_reset/locale/en/LC_MESSAGES/django.po b/password_reset/locale/en/LC_MESSAGES/django.po new file mode 100644 index 00000000..ec6d3d10 --- /dev/null +++ b/password_reset/locale/en/LC_MESSAGES/django.po @@ -0,0 +1,122 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-09-08 13:44+0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: password_reset/forms.py:14 +msgid "Sorry, this user doesn't exist." +msgstr "" + +#: password_reset/forms.py:31 +msgid "Username" +msgstr "" + +#: password_reset/forms.py:32 +msgid "Email" +msgstr "" + +#: password_reset/forms.py:33 +msgid "Для восстановления пароля укажите email, который Вы регистрировали" +msgstr "" + +#: password_reset/forms.py:83 +msgid "Unable to find user." +msgstr "" + +#: password_reset/forms.py:89 +msgid "New password" +msgstr "" + +#: password_reset/forms.py:93 +msgid "New password (confirm)" +msgstr "" + +#: password_reset/forms.py:98 +msgid "The two passwords didn't match." +msgstr "" + +#: password_reset/templates/password_reset/recovery_done.html:3 +msgid "New password set" +msgstr "" + +#: password_reset/templates/password_reset/recovery_done.html:6 +msgid "" +"Your password has successfully been reset. You can use it right now on the " +"login page." +msgstr "" + +#: password_reset/templates/password_reset/recovery_email.txt:1 +#, python-format +msgid "Dear %(username)s," +msgstr "" + +#: password_reset/templates/password_reset/recovery_email.txt:3 +#, python-format +msgid "" +"You -- or someone pretending to be you -- has requested a password reset on " +"%(domain)s." +msgstr "" + +#: password_reset/templates/password_reset/recovery_email.txt:5 +msgid "You can set your new password by following this link:" +msgstr "" + +#: password_reset/templates/password_reset/recovery_email.txt:9 +msgid "" +"If you don't want to reset your password, simply ignore this email and it " +"will stay unchanged." +msgstr "" + +#: password_reset/templates/password_reset/recovery_email_subject.txt:1 +#, python-format +msgid "Password recovery on %(domain)s" +msgstr "" + +#: password_reset/templates/password_reset/recovery_form.html:5 +msgid "Password recovery" +msgstr "" + +#: password_reset/templates/password_reset/recovery_form.html:10 +msgid "Recover my password" +msgstr "" + +#: password_reset/templates/password_reset/reset.html:5 +#, python-format +msgid "" +"Sorry, this password reset link is invalid. You can still request a new one." +msgstr "" + +#: password_reset/templates/password_reset/reset.html:7 +#, python-format +msgid "Hi, %(username)s. Please choose your new password." +msgstr "" + +#: password_reset/templates/password_reset/reset.html:11 +msgid "Set new password" +msgstr "" + +#: password_reset/templates/password_reset/reset_sent.html:4 +msgid "Password recovery sent" +msgstr "" + +#: password_reset/templates/password_reset/reset_sent.html:7 +#, python-format +msgid "" +"An email was sent to %(email)s %(ago)s ago. Use the link in " +"it to set a new password." +msgstr "" diff --git a/photologue/locale/en/LC_MESSAGES/django.po b/photologue/locale/en/LC_MESSAGES/django.po index a8029d7e..35d2d11d 100644 --- a/photologue/locale/en/LC_MESSAGES/django.po +++ b/photologue/locale/en/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Photologue\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-08-25 09:56+0000\n" +"POT-Creation-Date: 2015-09-08 13:44+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,171 +17,91 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: admin.py:67 -msgid "The following photo does not belong to the same site(s)" -msgid_plural "The following photos do not belong to the same site(s)" -msgstr[0] "" -msgstr[1] "" - -#: admin.py:79 -#, python-format -msgid "The gallery has been successfully added to %(site)s" -msgid_plural "The galleries have been successfully added to %(site)s" -msgstr[0] "" -msgstr[1] "" - -#: admin.py:86 -msgid "Add selected galleries from the current site" -msgstr "" - -#: admin.py:92 -#, python-format -msgid "The gallery has been successfully removed from %(site)s" -msgid_plural "" -"The selected galleries have been successfully removed from %(site)s" -msgstr[0] "" -msgstr[1] "" - -#: admin.py:99 -msgid "Remove selected galleries from the current site" -msgstr "" - -#: admin.py:106 -#, python-format -msgid "" -"All photos in gallery %(galleries)s have been successfully added to %(site)s" -msgid_plural "" -"All photos in galleries %(galleries)s have been successfully added to " -"%(site)s" -msgstr[0] "" -msgstr[1] "" - -#: admin.py:117 -msgid "Add all photos of selected galleries to the current site" -msgstr "" - -#: admin.py:124 -#, python-format -msgid "" -"All photos in gallery %(galleries)s have been successfully removed from " -"%(site)s" -msgid_plural "" -"All photos in galleries %(galleries)s have been successfully removed from " -"%(site)s" -msgstr[0] "" -msgstr[1] "" - -#: admin.py:135 -msgid "Remove all photos in selected galleries from the current site" -msgstr "" - -#: admin.py:186 -#, python-format -msgid "The photo has been successfully added to %(site)s" -msgid_plural "The selected photos have been successfully added to %(site)s" -msgstr[0] "" -msgstr[1] "" - -#: admin.py:193 -msgid "Add selected photos to the current site" -msgstr "" - -#: admin.py:199 -#, python-format -msgid "The photo has been successfully removed from %(site)s" -msgid_plural "The selected photos have been successfully removed from %(site)s" -msgstr[0] "" -msgstr[1] "" - -#: admin.py:206 -msgid "Remove selected photos from the current site" -msgstr "" - -#: models.py:56 +#: photologue/models.py:59 msgid "Separate tags with spaces, put quotes around multiple-word tags." msgstr "" -#: models.py:67 +#: photologue/models.py:70 msgid "Django-tagging was not found, tags will be treated as plain text." msgstr "" -#: models.py:115 +#: photologue/models.py:121 msgid "Very Low" msgstr "" -#: models.py:116 +#: photologue/models.py:122 msgid "Low" msgstr "" -#: models.py:117 +#: photologue/models.py:123 msgid "Medium-Low" msgstr "" -#: models.py:118 +#: photologue/models.py:124 msgid "Medium" msgstr "" -#: models.py:119 +#: photologue/models.py:125 msgid "Medium-High" msgstr "" -#: models.py:120 +#: photologue/models.py:126 msgid "High" msgstr "" -#: models.py:121 +#: photologue/models.py:127 msgid "Very High" msgstr "" -#: models.py:126 +#: photologue/models.py:132 msgid "Top" msgstr "" -#: models.py:127 +#: photologue/models.py:133 msgid "Right" msgstr "" -#: models.py:128 +#: photologue/models.py:134 msgid "Bottom" msgstr "" -#: models.py:129 +#: photologue/models.py:135 msgid "Left" msgstr "" -#: models.py:130 +#: photologue/models.py:136 msgid "Center (Default)" msgstr "" -#: models.py:134 +#: photologue/models.py:140 msgid "Flip left to right" msgstr "" -#: models.py:135 +#: photologue/models.py:141 msgid "Flip top to bottom" msgstr "" -#: models.py:136 +#: photologue/models.py:142 msgid "Rotate 90 degrees counter-clockwise" msgstr "" -#: models.py:137 +#: photologue/models.py:143 msgid "Rotate 90 degrees clockwise" msgstr "" -#: models.py:138 +#: photologue/models.py:144 msgid "Rotate 180 degrees" msgstr "" -#: models.py:142 +#: photologue/models.py:148 msgid "Tile" msgstr "" -#: models.py:143 +#: photologue/models.py:149 msgid "Scale" msgstr "" -#: models.py:154 +#: photologue/models.py:160 #, python-format msgid "" "Chain multiple filters using the following pattern \"FILTER_ONE->FILTER_TWO-" @@ -189,408 +109,505 @@ msgid "" "filters are available: %s." msgstr "" -#: models.py:159 -msgid "date published" +#: photologue/models.py:174 photologue/models.py:301 photologue/models.py:696 +msgid "title" msgstr "" -#: models.py:161 models.py:250 models.py:646 -msgid "title" +#: photologue/models.py:175 photologue/models.py:316 photologue/models.py:815 +msgid "description" msgstr "" -#: models.py:164 -msgid "title slug" +#: photologue/models.py:177 +msgid "date published" msgstr "" -#: models.py:166 models.py:651 -msgid "A \"slug\" is a unique URL-friendly title for an object." +#: photologue/models.py:180 +msgid "title slug" msgstr "" -#: models.py:167 models.py:263 models.py:730 -msgid "description" +#: photologue/models.py:182 photologue/models.py:704 +msgid "A \"slug\" is a unique URL-friendly title for an object." msgstr "" -#: models.py:169 models.py:266 models.py:656 +#: photologue/models.py:185 photologue/models.py:319 photologue/models.py:709 msgid "is public" msgstr "" -#: models.py:171 +#: photologue/models.py:187 msgid "Public galleries will be displayed in the default views." msgstr "" -#: models.py:175 models.py:669 +#: photologue/models.py:191 photologue/models.py:724 msgid "photos" msgstr "" -#: models.py:178 models.py:273 models.py:659 +#: photologue/models.py:197 photologue/models.py:326 photologue/models.py:712 msgid "tags" msgstr "" -#: models.py:179 models.py:660 +#: photologue/models.py:198 photologue/models.py:713 msgid "sites" msgstr "" -#: models.py:187 models.py:255 +#: photologue/models.py:206 photologue/models.py:308 msgid "gallery" msgstr "" -#: models.py:188 +#: photologue/models.py:207 msgid "galleries" msgstr "" -#: models.py:225 +#: photologue/models.py:276 msgid "count" msgstr "" -#: models.py:247 +#: photologue/models.py:298 msgid "images file (.zip)" msgstr "" -#: models.py:249 +#: photologue/models.py:300 msgid "Select a .zip file of images to upload into a new Gallery." msgstr "" -#: models.py:252 +#: photologue/models.py:305 msgid "" "All uploaded photos will be given a title made up of this title + a " "sequential number." msgstr "" -#: models.py:258 +#: photologue/models.py:311 msgid "" "Select a gallery to add these images to. Leave this empty to create a new " "gallery from the supplied title." msgstr "" -#: models.py:260 models.py:652 +#: photologue/models.py:313 photologue/models.py:698 msgid "caption" msgstr "" -#: models.py:262 +#: photologue/models.py:315 msgid "Caption will be added to all photos." msgstr "" -#: models.py:265 +#: photologue/models.py:318 msgid "A description of this Gallery." msgstr "" -#: models.py:268 +#: photologue/models.py:321 msgid "" "Uncheck this to make the uploaded gallery and included photographs private." msgstr "" -#: models.py:276 +#: photologue/models.py:329 msgid "gallery upload" msgstr "" -#: models.py:277 +#: photologue/models.py:330 msgid "gallery uploads" msgstr "" -#: models.py:289 +#: photologue/models.py:342 msgid "A gallery with that title already exists." msgstr "" -#: models.py:293 +#: photologue/models.py:346 msgid "Select an existing gallery or enter a new gallery name." msgstr "" -#: models.py:329 +#: photologue/models.py:382 +#, python-brace-format msgid "" "Ignoring file \"{filename}\" as it is in a subfolder; all images should be " "in the top folder of the zip." msgstr "" -#: models.py:349 -#, python-format +#: photologue/models.py:402 +#, python-format, python-brace-format msgid "" "Did not create photo \"%(filename)s\" with slug \"{1}\" as a photo with that " "slug already exists." msgstr "" -#: models.py:375 +#: photologue/models.py:428 +#, python-brace-format msgid "Could not process file \"{0}\" in the .zip archive." msgstr "" -#: models.py:392 models.py:863 +#: photologue/models.py:445 photologue/models.py:949 msgid "image" msgstr "" -#: models.py:395 +#: photologue/models.py:448 msgid "date taken" msgstr "" -#: models.py:399 +#: photologue/models.py:452 msgid "view count" msgstr "" -#: models.py:402 +#: photologue/models.py:455 msgid "crop from" msgstr "" -#: models.py:411 +#: photologue/models.py:464 msgid "effect" msgstr "" -#: models.py:429 +#: photologue/models.py:488 msgid "An \"admin_thumbnail\" photo size has not been defined." msgstr "" -#: models.py:437 +#: photologue/models.py:496 msgid "Thumbnail" msgstr "" -#: models.py:649 +#: photologue/models.py:702 msgid "slug" msgstr "" -#: models.py:654 +#: photologue/models.py:707 msgid "date added" msgstr "" -#: models.py:658 +#: photologue/models.py:711 msgid "Public photographs will be displayed in the default views." msgstr "" -#: models.py:668 +#: photologue/models.py:723 msgid "photo" msgstr "" -#: models.py:727 models.py:889 +#: photologue/models.py:812 photologue/models.py:981 msgid "name" msgstr "" -#: models.py:801 +#: photologue/models.py:887 msgid "rotate or flip" msgstr "" -#: models.py:805 models.py:827 +#: photologue/models.py:891 photologue/models.py:913 msgid "color" msgstr "" -#: models.py:807 +#: photologue/models.py:893 msgid "" "A factor of 0.0 gives a black and white image, a factor of 1.0 gives the " "original image." msgstr "" -#: models.py:808 +#: photologue/models.py:894 msgid "brightness" msgstr "" -#: models.py:810 +#: photologue/models.py:896 msgid "" "A factor of 0.0 gives a black image, a factor of 1.0 gives the original " "image." msgstr "" -#: models.py:811 +#: photologue/models.py:897 msgid "contrast" msgstr "" -#: models.py:813 +#: photologue/models.py:899 msgid "" "A factor of 0.0 gives a solid grey image, a factor of 1.0 gives the original " "image." msgstr "" -#: models.py:814 +#: photologue/models.py:900 msgid "sharpness" msgstr "" -#: models.py:816 +#: photologue/models.py:902 msgid "" "A factor of 0.0 gives a blurred image, a factor of 1.0 gives the original " "image." msgstr "" -#: models.py:817 +#: photologue/models.py:903 msgid "filters" msgstr "" -#: models.py:821 +#: photologue/models.py:907 msgid "size" msgstr "" -#: models.py:823 +#: photologue/models.py:909 msgid "" "The height of the reflection as a percentage of the orignal image. A factor " "of 0.0 adds no reflection, a factor of 1.0 adds a reflection equal to the " "height of the orignal image." msgstr "" -#: models.py:824 +#: photologue/models.py:910 msgid "strength" msgstr "" -#: models.py:826 +#: photologue/models.py:912 msgid "The initial opacity of the reflection gradient." msgstr "" -#: models.py:830 +#: photologue/models.py:916 msgid "" "The background color of the reflection gradient. Set this to match the " "background color of your page." msgstr "" -#: models.py:833 models.py:924 +#: photologue/models.py:919 photologue/models.py:1016 msgid "photo effect" msgstr "" -#: models.py:834 +#: photologue/models.py:920 msgid "photo effects" msgstr "" -#: models.py:865 +#: photologue/models.py:951 msgid "style" msgstr "" -#: models.py:869 +#: photologue/models.py:955 msgid "opacity" msgstr "" -#: models.py:871 +#: photologue/models.py:957 msgid "The opacity of the overlay." msgstr "" -#: models.py:874 +#: photologue/models.py:960 msgid "watermark" msgstr "" -#: models.py:875 +#: photologue/models.py:961 msgid "watermarks" msgstr "" -#: models.py:893 +#: photologue/models.py:985 msgid "" "Photo size name should contain only letters, numbers and underscores. " "Examples: \"thumbnail\", \"display\", \"small\", \"main_page_widget\"." msgstr "" -#: models.py:898 +#: photologue/models.py:990 msgid "width" msgstr "" -#: models.py:900 +#: photologue/models.py:992 msgid "" "If width is set to \"0\" the image will be scaled to the supplied height." msgstr "" -#: models.py:901 +#: photologue/models.py:993 msgid "height" msgstr "" -#: models.py:903 +#: photologue/models.py:995 msgid "" "If height is set to \"0\" the image will be scaled to the supplied width" msgstr "" -#: models.py:904 +#: photologue/models.py:996 msgid "quality" msgstr "" -#: models.py:907 +#: photologue/models.py:999 msgid "JPEG image quality." msgstr "" -#: models.py:908 +#: photologue/models.py:1000 msgid "upscale images?" msgstr "" -#: models.py:910 +#: photologue/models.py:1002 msgid "" "If selected the image will be scaled up if necessary to fit the supplied " "dimensions. Cropped sizes will be upscaled regardless of this setting." msgstr "" -#: models.py:911 +#: photologue/models.py:1003 msgid "crop to fit?" msgstr "" -#: models.py:913 +#: photologue/models.py:1005 msgid "" "If selected the image will be scaled and cropped to fit the supplied " "dimensions." msgstr "" -#: models.py:914 +#: photologue/models.py:1006 msgid "pre-cache?" msgstr "" -#: models.py:916 +#: photologue/models.py:1008 msgid "If selected this photo size will be pre-cached as photos are added." msgstr "" -#: models.py:917 +#: photologue/models.py:1009 msgid "increment view count?" msgstr "" -#: models.py:919 +#: photologue/models.py:1011 msgid "" "If selected the image's \"view_count\" will be incremented when this photo " "size is displayed." msgstr "" -#: models.py:929 +#: photologue/models.py:1021 msgid "watermark image" msgstr "" -#: models.py:933 +#: photologue/models.py:1025 msgid "photo size" msgstr "" -#: models.py:934 +#: photologue/models.py:1026 msgid "photo sizes" msgstr "" -#: models.py:951 +#: photologue/models.py:1043 msgid "Can only crop photos if both width and height dimensions are set." msgstr "" -#: contrib/bootstrap/templates/photologue/gallery_archive.html:5 -#: contrib/bootstrap/templates/photologue/gallery_archive.html:11 +#: photologue/templates/photologue/gallery_archive.html:4 +#: photologue/templates/photologue/gallery_archive.html:9 msgid "Latest Photo Galleries" msgstr "" -#: contrib/bootstrap/templates/photologue/gallery_archive.html:20 -#: contrib/bootstrap/templates/photologue/gallery_detail.html:12 -#: contrib/bootstrap/templates/photologue/gallery_list.html:20 -#: contrib/bootstrap/templates/photologue/photo_detail.html:13 -msgid "Published" +#: photologue/templates/photologue/gallery_archive.html:14 +#: photologue/templates/photologue/photo_archive.html:16 +msgid "Filter by year" msgstr "" -#: contrib/bootstrap/templates/photologue/gallery_archive.html:31 -#: contrib/bootstrap/templates/photologue/gallery_list.html:31 +#: photologue/templates/photologue/gallery_archive.html:30 +#: photologue/templates/photologue/gallery_list.html:30 msgid "No galleries were found" msgstr "" -#: contrib/bootstrap/templates/photologue/gallery_archive.html:36 -#: contrib/bootstrap/templates/photologue/gallery_detail.html:21 +#: photologue/templates/photologue/gallery_archive_day.html:4 +#: photologue/templates/photologue/gallery_archive_day.html:8 +#, python-format +msgid "Galleries for %(show_day)s" +msgstr "" + +#: photologue/templates/photologue/gallery_archive_day.html:15 +#: photologue/templates/photologue/gallery_archive_month.html:30 +#: photologue/templates/photologue/gallery_archive_year.html:30 +msgid "No galleries were found." +msgstr "" + +#: photologue/templates/photologue/gallery_archive_day.html:19 +msgid "View all galleries for month" +msgstr "" + +#: photologue/templates/photologue/gallery_archive_month.html:4 +#: photologue/templates/photologue/gallery_archive_month.html:9 +#, python-format +msgid "Galleries for %(show_month)s" +msgstr "" + +#: photologue/templates/photologue/gallery_archive_month.html:14 +#: photologue/templates/photologue/photo_archive_month.html:14 +msgid "Filter by day" +msgstr "" + +#: photologue/templates/photologue/gallery_archive_month.html:34 +msgid "View all galleries for year" +msgstr "" + +#: photologue/templates/photologue/gallery_archive_year.html:4 +#: photologue/templates/photologue/gallery_archive_year.html:9 +#, python-format +msgid "Galleries for %(show_year)s" +msgstr "" + +#: photologue/templates/photologue/gallery_archive_year.html:14 +#: photologue/templates/photologue/photo_archive_year.html:15 +msgid "Filter by month" +msgstr "" + +#: photologue/templates/photologue/gallery_archive_year.html:34 +#: photologue/templates/photologue/gallery_detail.html:20 msgid "View all galleries" msgstr "" -#: contrib/bootstrap/templates/photologue/gallery_list.html:5 -#: contrib/bootstrap/templates/photologue/gallery_list.html:11 +#: photologue/templates/photologue/gallery_detail.html:11 +#: photologue/templates/photologue/gallery_list.html:19 +#: photologue/templates/photologue/includes/gallery_sample.html:8 +#: photologue/templates/photologue/photo_detail.html:13 +msgid "Published" +msgstr "" + +#: photologue/templates/photologue/gallery_list.html:4 +#: photologue/templates/photologue/gallery_list.html:10 msgid "All Galleries" msgstr "" -#: contrib/bootstrap/templates/photologue/gallery_list.html:37 -#: contrib/bootstrap/templates/photologue/gallery_list.html:39 +#: photologue/templates/photologue/includes/paginator.html:5 +#: photologue/templates/photologue/includes/paginator.html:7 msgid "Previous" msgstr "" -#: contrib/bootstrap/templates/photologue/gallery_list.html:42 +#: photologue/templates/photologue/includes/paginator.html:10 #, python-format msgid "" "\n" -"\t\t\t\t page %(page_number)s of %(total_pages)s\n" -"\t\t\t\t" +"\t\t\t page %(page_number)s of %(total_pages)s\n" +"\t\t\t" msgstr "" -#: contrib/bootstrap/templates/photologue/gallery_list.html:47 -#: contrib/bootstrap/templates/photologue/gallery_list.html:49 +#: photologue/templates/photologue/includes/paginator.html:15 +#: photologue/templates/photologue/includes/paginator.html:17 msgid "Next" msgstr "" -#: contrib/bootstrap/templates/photologue/photo_detail.html:21 +#: photologue/templates/photologue/photo_archive.html:4 +#: photologue/templates/photologue/photo_archive.html:10 +msgid "Latest Photos" +msgstr "" + +#: photologue/templates/photologue/photo_archive.html:36 +#: photologue/templates/photologue/photo_archive_day.html:19 +#: photologue/templates/photologue/photo_archive_month.html:34 +#: photologue/templates/photologue/photo_archive_year.html:35 +#: photologue/templates/photologue/photo_list.html:23 +msgid "No photos were found" +msgstr "" + +#: photologue/templates/photologue/photo_archive_day.html:4 +#: photologue/templates/photologue/photo_archive_day.html:8 +#, python-format +msgid "Photos for %(show_day)s" +msgstr "" + +#: photologue/templates/photologue/photo_archive_day.html:23 +msgid "View all photos for month" +msgstr "" + +#: photologue/templates/photologue/photo_archive_month.html:4 +#: photologue/templates/photologue/photo_archive_month.html:9 +#, python-format +msgid "Photos for %(show_month)s" +msgstr "" + +#: photologue/templates/photologue/photo_archive_month.html:38 +msgid "View all photos for year" +msgstr "" + +#: photologue/templates/photologue/photo_archive_year.html:4 +#: photologue/templates/photologue/photo_archive_year.html:10 +#, python-format +msgid "Photos for %(show_year)s" +msgstr "" + +#: photologue/templates/photologue/photo_archive_year.html:39 +msgid "View all photos" +msgstr "" + +#: photologue/templates/photologue/photo_detail.html:21 msgid "This photo is found in the following galleries" msgstr "" + +#: photologue/templates/photologue/photo_list.html:4 +#: photologue/templates/photologue/photo_list.html:10 +msgid "All Photos" +msgstr "" diff --git a/proj/admin_urls.py b/proj/admin_urls.py index 47bbfeaf..8cd0455a 100644 --- a/proj/admin_urls.py +++ b/proj/admin_urls.py @@ -34,6 +34,7 @@ urlpatterns = required( url(r'^settings/', include('settings.admin_urls')), url(r'^meta/', include('meta.admin_urls')), url(r'^import_xls/', include('import_xls.admin_urls')), + url(r'^translator_catalog/', include('specialist_catalog.admin_urls')), url(r'^language/add/', 'directories.admin.language_add'), url(r'^currency/add/', 'directories.admin.currency_add'), diff --git a/proj/decorators.py b/proj/decorators.py index f3f48c8d..149b9358 100644 --- a/proj/decorators.py +++ b/proj/decorators.py @@ -1,16 +1,16 @@ -from functools import wraps - -from django.template import RequestContext -from django.shortcuts import render_to_response - - -def render_to(tpl): - def decorator(func): - @wraps(func) - def wrapper(request, *args, **kwargs): - out = func(request, *args, **kwargs) - if isinstance(out, dict): - out = render_to_response(tpl, out, RequestContext(request)) - return out - return wrapper +from functools import wraps + +from django.template import RequestContext +from django.shortcuts import render_to_response + + +def render_to(tpl): + def decorator(func): + @wraps(func) + def wrapper(request, *args, **kwargs): + out = func(request, *args, **kwargs) + if isinstance(out, dict): + out = render_to_response(tpl, out, RequestContext(request)) + return out + return wrapper return decorator \ No newline at end of file diff --git a/proj/settings.py b/proj/settings.py index 14caba29..9fdca037 100644 --- a/proj/settings.py +++ b/proj/settings.py @@ -242,7 +242,6 @@ SOCIAL_AUTH_INACTIVE_USER_URL = '/inactive-user/' SOCIAL_AUTH_USERNAME_IS_FULL_EMAIL = True -from social.pipeline.social_auth import social_details SOCIAL_AUTH_PIPELINE = ( 'social.pipeline.social_auth.social_details', 'social.pipeline.social_auth.social_uid', @@ -354,6 +353,7 @@ INSTALLED_APPS = ( 'password_reset', # reset password 'social.apps.django_app.default', # social auth 'core', + 'specialist_catalog', ) diff --git a/proj/urls.py b/proj/urls.py index 085e5bf1..f6c375fe 100644 --- a/proj/urls.py +++ b/proj/urls.py @@ -29,6 +29,7 @@ sitemaps = { handler404 = 'proj.views.error404' urlpatterns = patterns('', + url(r'^acquire_email/$', 'registration.backends.default.views.acquire_email', name = 'acquire_email'), url(r'^rss/', include('core.urls')), #url(r'^__debug__/', include(debug_toolbar.urls)), url(r'^sitemap-(?P
.+)\.xml$', views.sitemap, {'sitemaps': sitemaps}), @@ -42,7 +43,8 @@ urlpatterns = patterns('', url(r'^page/', include('core.simple_urls')), url(r'^theme/', include('theme.urls')), url(r'^places/', include('place_exposition.urls')), - url(r'^translators/', include('translator.urls')), + #url(r'^translators/', include('translator.urls')), + url(r'^translators/', include('specialist_catalog.urls')), url(r'^expo-b/', include('expobanner.urls')), url(r'^', include('accounts.urls')), url(r'^', include('exposition.urls')), diff --git a/registration/locale/en/LC_MESSAGES/django.po b/registration/locale/en/LC_MESSAGES/django.po index e357a4ce..2c065815 100644 --- a/registration/locale/en/LC_MESSAGES/django.po +++ b/registration/locale/en/LC_MESSAGES/django.po @@ -8,82 +8,107 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-10-12 14:09-0500\n" +"POT-Creation-Date: 2015-09-08 13:44+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: admin.py:23 +#: registration/admin.py:23 msgid "Activate users" msgstr "" -#: admin.py:43 +#: registration/admin.py:43 msgid "Re-send activation emails" msgstr "" -#: forms.py:35 -msgid "username" +#: registration/backends/default/views.py:197 +msgid "Пользователя с таким email не существует" msgstr "" -#: forms.py:36 -msgid "This value must contain only letters, numbers and underscores." +#: registration/backends/default/views.py:200 +msgid "Пользователя с таким email уже активирован" msgstr "" -#: forms.py:39 -msgid "Email address" +#: registration/forms.py:44 +msgid "First name" msgstr "" -#: forms.py:41 -msgid "Password" +#: registration/forms.py:45 registration/forms.py:50 +msgid "This value may contain only letters, numbers and @/./+/-/_ characters." msgstr "" -#: forms.py:43 -msgid "Password (again)" +#: registration/forms.py:46 +msgid "Имя" +msgstr "" + +#: registration/forms.py:49 +msgid "Last name" +msgstr "" + +#: registration/forms.py:51 +msgid "Фамилия" +msgstr "" + +#: registration/forms.py:53 +msgid "E-mail" msgstr "" -#: forms.py:55 -msgid "A user with that username already exists." +#: registration/forms.py:53 +msgid "Адрес электронной почты" msgstr "" -#: forms.py:67 -msgid "The two password fields didn't match." +#: registration/forms.py:54 +msgid "Придумайте пароль" +msgstr "" + +#: registration/forms.py:55 +msgid "Password" +msgstr "" + +#: registration/forms.py:56 +msgid "Повторите пароль" +msgstr "" + +#: registration/forms.py:57 +msgid "Password (again)" msgstr "" -#: forms.py:78 +#: registration/forms.py:83 msgid "I have read and agree to the Terms of Service" msgstr "" -#: forms.py:79 +#: registration/forms.py:84 msgid "You must agree to the terms to register" msgstr "" -#: forms.py:95 +#: registration/forms.py:100 msgid "" "This email address is already in use. Please supply a different email " "address." msgstr "" -#: forms.py:122 +#: registration/forms.py:127 msgid "" "Registration using free email addresses is prohibited. Please supply a " "different email address." msgstr "" -#: models.py:165 +#: registration/models.py:184 msgid "user" msgstr "" -#: models.py:166 +#: registration/models.py:185 msgid "activation key" msgstr "" -#: models.py:171 +#: registration/models.py:190 msgid "registration profile" msgstr "" -#: models.py:172 +#: registration/models.py:191 msgid "registration profiles" msgstr "" diff --git a/service/urls.py b/service/urls.py index 10efb29a..5b3055a5 100644 --- a/service/urls.py +++ b/service/urls.py @@ -4,7 +4,7 @@ from views import ServiceView, CallBackListView, VisitListView, TranslationListV ParticipationListView, RemoteListView,TicketsListView, Thanks urlpatterns = patterns('', - url(r'service/thanks/$', Thanks.as_view()), + url(r'service/thanks/$', Thanks.as_view(), name = "service_thanks"), url(r'service/com_rek/(?P.*)/(?P.*)/$', 'service.views.advertise'), 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 9fbc0586..a88e3766 100644 --- a/service/views.py +++ b/service/views.py @@ -46,7 +46,6 @@ class ServiceView(MetadataMixin, FormView): def form_valid(self, form): order = form.save(commit=False) order.save() - #messages.success(self.request, _(u'Ваш запрос был успешно отправлен')) return HttpResponseRedirect(self.success_url) def get_context_data(self, **kwargs): diff --git a/specialist_catalog/__init__.py b/specialist_catalog/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/specialist_catalog/admin_urls.py b/specialist_catalog/admin_urls.py new file mode 100644 index 00000000..df5e4ea6 --- /dev/null +++ b/specialist_catalog/admin_urls.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +from django.conf.urls import url, patterns +from .views import * + +urlpatterns = patterns('', + url(r'^specialist/new/$', SpecialistCreateView.as_view(), name='specialist_new'), + url(r'^specialist/all/$', SpecialistListView.as_view(), name='specialist_all'), + url(r'^specialist/edit/(?P\d{1,4})/$', SpecialistUpdateView.as_view(), name='specialist_edit'), + url(r'^specialist/delete/(?P\d{1,4})/$', SpecialistDeleteView.as_view(), name='specialist_delete'), + url(r'^catalog/new/$', CatalogCreateView.as_view(), name='catalog_new'), + url(r'^catalog/all/$', CatalogListView.as_view(), name='catalog_all'), + url(r'^catalog/city/$', CatalogCityView.as_view(), name='catalog_city'), + url(r'^catalog/country/$', CatalogCountryView.as_view(), name='catalog_country'), + url(r'^catalog/edit/(?P\d{1,4})/$', CatalogUpdateView.as_view(), name='catalog_edit'), + url(r'^catalog/delete/(?P\d{1,4})/$', CatalogDeleteView.as_view(), name='catalog_delete'), + url(r'^catalog/(?P\d{1,4})/add_feedback/$', FeedbackCreateView.as_view(), name='feedback_new'), + #url(r'^catalog/(?P\d{1,4})/feedbacks/$', FeedbackListView.as_view(), name='feedback_all'), + url(r'^catalog/(?P\d{1,4})/feedback/(?P\d{1,4})/$', FeedbackUpdateView.as_view(), name='feedback_edit'), + url(r'^feedback/delete/(?P\d{1,4})/$', FeedbackDeleteView.as_view(), name='feedback_delete'), +) \ No newline at end of file diff --git a/specialist_catalog/forms.py b/specialist_catalog/forms.py new file mode 100644 index 00000000..5bdb1388 --- /dev/null +++ b/specialist_catalog/forms.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- +from django import forms +from hvad.forms import TranslatableModelForm +from .models import Specialist, SpecialistCatalog, Feedback, City, Country +from ckeditor.widgets import CKEditorWidget +from django.utils.translation import get_language + +country_choices = [(c.id, c.name) for c in Country.objects.all()] +lang_code = get_language()[:2] + +default_text = u"Планируете посетить выставку в %s?" \ + u" Мы предлагаем Вам подобрать переводчика именно под Ваши цели и потребности. " \ + u"Специализируясь уже более 7 лет на предоставлении переводчиков на выставки и конференции " \ + u"%s, мы можем предоставить профессионалов со знанием разных " \ + u"языков на гибких для Вас условиях. Каждый заказ индивидуален для нас, " \ + u"и итоговая цена зависит от вида перевода, тематики, срочности подбора " \ + u"специалиста, города и объема работы." +default_title = u"Переводчики в %s" + + +class SpecialistCatalogForm(TranslatableModelForm): + + class Meta: + model = SpecialistCatalog + fields = ['price', 'currency', 'logo_preview', 'main_descr', 'place_photo', + 'specialists', 'city', 'country', 'type', 'title', 'benefits', 'big_cities'] + widgets = { + 'type': forms.Select(choices=(('1', 'Country'), ('2', 'City'))), + 'city': forms.HiddenInput(attrs={'id': 'id_city'}), + 'country': forms.Select(choices=country_choices, attrs={'id': 'id_country'}), + 'main_descr': CKEditorWidget, + 'benefits': CKEditorWidget, + 'big_cities': CKEditorWidget, + } + + def save(self, commit=True): + place = self.cleaned_data.get('city') or self.cleaned_data.get('country') + place_inflect = place.inflect or place.name + if not self.cleaned_data['title']: + self.cleaned_data['title'] = default_title % place_inflect + if not self.cleaned_data['main_descr']: + self.cleaned_data['main_descr'] = default_text % (place_inflect, place_inflect) + return super(SpecialistCatalogForm, self).save(commit=True) + + +class SpecialistForm(forms.ModelForm): + + class Meta: + model = Specialist + fields = ['name','country', 'city', 'photo', 'languages'] + widgets = { + 'city': forms.HiddenInput(attrs={'id': 'id_city'}), + 'country': forms.Select(choices=country_choices, attrs={'id': 'id_country'}) + } + + +class FeedbackForm(forms.ModelForm): + + class Meta: + model = Feedback + fields = ['company', 'name', 'text', 'logo', 'catalog'] + widgets = { + 'text':CKEditorWidget + } + diff --git a/specialist_catalog/management/__init__.py b/specialist_catalog/management/__init__.py new file mode 100644 index 00000000..b29e46c3 --- /dev/null +++ b/specialist_catalog/management/__init__.py @@ -0,0 +1 @@ +__author__ = 'dart_vaider' diff --git a/specialist_catalog/management/commands/__init__.py b/specialist_catalog/management/commands/__init__.py new file mode 100644 index 00000000..b29e46c3 --- /dev/null +++ b/specialist_catalog/management/commands/__init__.py @@ -0,0 +1 @@ +__author__ = 'dart_vaider' diff --git a/specialist_catalog/management/commands/create_city_page.py b/specialist_catalog/management/commands/create_city_page.py new file mode 100644 index 00000000..68ce4ac9 --- /dev/null +++ b/specialist_catalog/management/commands/create_city_page.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +from django.core.management.base import BaseCommand +from django.utils.translation import activate +from city.models import City +from specialist_catalog.models import SpecialistCatalog + +default_text = u"Планируете посетить выставку %s?" \ + u" Мы предлагаем Вам подобрать переводчика именно под Ваши цели и потребности. " \ + u"Специализируясь уже более 7 лет на предоставлении переводчиков на выставки и конференции " \ + u"%s, мы можем предоставить профессионалов со знанием разных " \ + u"языков на гибких для Вас условиях. Каждый заказ индивидуален для нас, " \ + u"и итоговая цена зависит от вида перевода, тематики, срочности подбора " \ + u"специалиста, города и объема работы." +default_title = u"Переводчики %s" + +default_benefits = """
    +
  • Эффективная цена
  • +
  • Опыт и профессионализм специалистов
  • +
  • Знание разных менталитетов и психологических аспектов проведения переговоров с зарубежными бизнесменами
  • +
  • Ориентированность в мировых выставочных комплексах
  • +
  • Гарантии, отчетность по договору, прозрачные безналичные расчеты в России
  • +
""" + + + +class Command(BaseCommand): + def handle(self, *args, **options): + activate('ru') + cities = set(City.used.expo_cities()) + for cty in cities: + name = cty.inflect or cty.name + sc = SpecialistCatalog( + type=2, + country=cty.country, + city=cty, + title=default_title % name, + main_descr=default_text % (name, name), + benefits = default_benefits + ) + sc.save() + print cty.url, " -> ", cty.country.url diff --git a/specialist_catalog/management/commands/create_country_page.py b/specialist_catalog/management/commands/create_country_page.py new file mode 100644 index 00000000..4910f81b --- /dev/null +++ b/specialist_catalog/management/commands/create_country_page.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +from django.core.management.base import BaseCommand +from django.utils.translation import activate +from country.models import Country +from specialist_catalog.models import SpecialistCatalog +from django.utils.translation import activate + +activate('ru') + +default_text = u"Планируете посетить выставку %s?" \ + u" Мы предлагаем Вам подобрать переводчика именно под Ваши цели и потребности. " \ + u"Специализируясь уже более 7 лет на предоставлении переводчиков на выставки и конференции " \ + u"%s, мы можем предоставить профессионалов со знанием разных " \ + u"языков на гибких для Вас условиях. Каждый заказ индивидуален для нас, " \ + u"и итоговая цена зависит от вида перевода, тематики, срочности подбора " \ + u"специалиста, города и объема работы." +default_title = u"Переводчики %s" +default_benefits = """
    +
  • Эффективная цена
  • +
  • Опыт и профессионализм специалистов
  • +
  • Знание разных менталитетов и психологических аспектов проведения переговоров с зарубежными бизнесменами
  • +
  • Ориентированность в мировых выставочных комплексах
  • +
  • Гарантии, отчетность по договору, прозрачные безналичные расчеты в России
  • +
""" + + +class Command(BaseCommand): + def handle(self, *args, **options): + activate('ru') + countries = set(Country.objects.expo_countries()) + + for cntry in countries: + name = cntry.inflect or cntry.name + sc = SpecialistCatalog( + type='1', + country=cntry, + title=default_title % name, + main_descr=default_text % (name, name), + benefits = default_benefits + ) + sc.save() + print "created for: %s" % cntry.url diff --git a/specialist_catalog/models.py b/specialist_catalog/models.py new file mode 100644 index 00000000..36a7b578 --- /dev/null +++ b/specialist_catalog/models.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +from django.db import models +from django.conf import settings +from hvad.models import TranslatableModel, TranslatedFields, TranslationManager +from city.models import City +from country.models import Country +from django.core.urlresolvers import reverse_lazy +from django.utils.translation import get_language +import copy + +# types of catalog +_country = 1 +_city = 2 + + +class Specialist(models.Model): + name = models.CharField(max_length=255, verbose_name=u"Полное имя", blank=False) + languages = models.CharField(max_length=255, verbose_name=u"Языки") + city = models.ForeignKey(City, on_delete=models.PROTECT, verbose_name=u"Город", blank=True) + country = models.ForeignKey(Country, on_delete=models.PROTECT, verbose_name=u"Страна") + photo = models.ImageField(verbose_name=u"Фото", upload_to="specialist_catalog/specialist_photo/", blank=True) + + + def __unicode__(self): + return u"%s" % self.name + + +class SpecialistCatalog(TranslatableModel): + price = models.IntegerField(verbose_name=u"Цена", default=200) + currency = models.CharField(max_length=255, verbose_name=u"Валюта", default=u"EUR") + logo_preview = models.ImageField(verbose_name=u"Логотип", blank=True, upload_to='specialist_catalog/logo_preview/') + place_photo = models.ImageField(verbose_name=u"Фото для города", blank=True, upload_to='specialist_catalog/place_photo/') + specialists = models.ManyToManyField(Specialist, verbose_name=u"Специалисты", blank=True) + city = models.ForeignKey(City, on_delete=models.PROTECT, verbose_name=u"Город", blank=True, null=True) + country = models.ForeignKey(Country, on_delete=models.PROTECT, verbose_name=u"Страна", blank=False) + type = models.PositiveSmallIntegerField(verbose_name=u"Тип(Страна/Город)", default=2) + + + translations = TranslatedFields( + title=models.CharField(max_length=255, verbose_name=u"Заголовок"), + main_descr=models.CharField(max_length=1000, verbose_name=u"Краткое описание"), + benefits=models.CharField(max_length=2000, verbose_name=u"Преимущества"), + big_cities=models.TextField(verbose_name=u"Крупные города", blank=True) + ) + + def __init__(self, *args, **kwargs): + super(SpecialistCatalog, self).__init__(*args, **kwargs) + self.cache_fields = ['title', 'main_descr', 'benefits'] + self.is_new = True + + def get_absolute_url(self): + global _country, _city + if self.type == _country: + return reverse_lazy('spec_catalog_country', kwargs={'slug': self.country.url}) + return reverse_lazy('spec_catalog_city', kwargs={'slug': self.city.url}) + + def save(self, *args, **kwargs): + super(SpecialistCatalog, self).save(*args, **kwargs) + self.initial_language = get_language()[:2] or 'ru' + + new_values = {field: getattr(self, field) for field in self.cache_fields} + langs = [code for code, _ in settings.LANGUAGES] + if self.is_new: + for lang in langs: + if lang not in self.get_available_languages(): + self.translate(lang) + for key, value in new_values.items(): + setattr(self, key, value) + self.save_translations(self) + else: + translations = {obj.language_code: obj for obj in list(self.translations.all())} + for lang in langs: + if lang is not self.initial_language: + tr = translations[lang] + for key, value in new_values.items(): + #if u'%s' % getattr(tr, key) is u'%s' % self.var_cache[key]: + setattr(tr, key, value) + tr.save() + + self.lazy_translation_getter(self.initial_language) + self.var_cache = {var: copy.copy(getattr(self, var)) for var in self.cache_fields} + self.is_new = False + return self + + def __unicode__(self): + return self.lazy_translation_getter('title', unicode(self.pk)) + + def place(self): + if self.type == _country: + return self.country + elif self.type == _city: + return self.city + else: + return None + + +class Feedback(models.Model): + company = models.CharField(max_length=255, verbose_name=u"Название компании") + name = models.CharField(max_length=100, verbose_name=u"Имя") + text = models.CharField(max_length=5000, verbose_name=u"Текст отзыва") + logo = models.ImageField(verbose_name=u"Логотип компании", upload_to='specialist_catalog/feedback_logo/', blank=True) + catalog = models.ForeignKey(SpecialistCatalog, verbose_name=u"Страница", blank=False) + + def __unicode__(self): + return "Feedback from %s" % self.company + + diff --git a/specialist_catalog/tests.py b/specialist_catalog/tests.py new file mode 100644 index 00000000..501deb77 --- /dev/null +++ b/specialist_catalog/tests.py @@ -0,0 +1,16 @@ +""" +This file demonstrates writing tests using the unittest module. These will pass +when you run "manage.py test". + +Replace this with more appropriate tests for your application. +""" + +from django.test import TestCase + + +class SimpleTest(TestCase): + def test_basic_addition(self): + """ + Tests that 1 + 1 always equals 2. + """ + self.assertEqual(1 + 1, 2) diff --git a/specialist_catalog/urls.py b/specialist_catalog/urls.py new file mode 100644 index 00000000..91382837 --- /dev/null +++ b/specialist_catalog/urls.py @@ -0,0 +1,11 @@ +# -*- coding: utf-8 -*- +from django.conf.urls import url, patterns +from .views import CatalogDetailedView, SpecCatalog + +urlpatterns = patterns('', + url(r'^city/$', SpecCatalog.as_view(), {'type': 'city'}, name="spec_city"), + url(r'^country/$', SpecCatalog.as_view(), {'type': 'country'}, name="spec_country"), + + url(r'^city/(?P.*)/$', CatalogDetailedView.as_view(), {'type': 'city'}, name="spec_catalog_city"), + url(r'^country/(?P.*)/$', CatalogDetailedView.as_view(), {'type': 'country'}, name="spec_catalog_country"), +) \ No newline at end of file diff --git a/specialist_catalog/views.py b/specialist_catalog/views.py new file mode 100644 index 00000000..b7ed1b44 --- /dev/null +++ b/specialist_catalog/views.py @@ -0,0 +1,225 @@ +# -*- coding: utf-8 -*- +from django.views.generic import CreateView, UpdateView, DeleteView, ListView, FormView, DetailView +from django.views.generic.detail import SingleObjectMixin +from django.utils.translation import ugettext as _ +from .forms import * +from django.core.urlresolvers import reverse_lazy +from django.conf import settings +from django.shortcuts import get_object_or_404 +from service.order_forms import TranslationForm +from django.http import HttpResponseRedirect, Http404 +from .models import _city, _country + + +# =========== ADMIN VIEWS =========== + +# Specialist views + + +class SpecialistCreateView(CreateView): + form_class = SpecialistForm + model = Specialist + template_name = 'admin/specialist/specialist_new.html' + success_url = reverse_lazy("specialist_all") + + +from hvad.utils import get_translation_aware_manager + + +class SpecialistListView(ListView): + model = Specialist + template_name = 'admin/specialist/specialist_all.html' + paginate_by = settings.ADMIN_PAGINATION + + def get_queryset(self): + name = self.request.GET.get('name', None) + city = self.request.GET.get('city', None) + qs = get_translation_aware_manager(Specialist).all() + if name: + qs = qs.filter(name__icontains=name) + if city: + qs = qs.filter(city__name__icontains=city) + return qs + + +class SpecialistUpdateView(UpdateView): + form_class = SpecialistForm + model = Specialist + template_name = 'admin/specialist/specialist_new.html' + success_url = reverse_lazy("specialist_all") + + def get_form(self, form_class): + form = super(SpecialistUpdateView, self).get_form(form_class) + form.fields['city'].widget.attrs['data-init-text'] = self.object.city.name + return form + + +class SpecialistDeleteView(DeleteView): + model = Specialist + template_name = 'admin/specialist/specialist_confirm_delete.html' + success_url = reverse_lazy("specialist_all") + + +# Catalog views + + +class CatalogCreateView(CreateView): + form_class = SpecialistCatalogForm + model = SpecialistCatalog + template_name = 'admin/specialist/catalog_new.html' + success_url = reverse_lazy("catalog_all") + + +class CatalogListView(ListView): + model = SpecialistCatalog + template_name = 'admin/specialist/catalog_all.html' + paginate_by = settings.ADMIN_PAGINATION + + +class CatalogCityView(ListView): + model = SpecialistCatalog + template_name = 'admin/specialist/catalog_all.html' + paginate_by = settings.ADMIN_PAGINATION + + def get_queryset(self): + query = self.request.GET.get('query', None) + qs = self.model.objects.language().filter(type=2) + if query: + qs = qs.filter(title__icontains=query) + return qs + + +class CatalogCountryView(ListView): + model = SpecialistCatalog + template_name = 'admin/specialist/catalog_all.html' + paginate_by = settings.ADMIN_PAGINATION + + def get_queryset(self): + query = self.request.GET.get('query', None) + qs = self.model.objects.language().filter(type=1) + if query: + qs = qs.filter(title__icontains=query) + return qs + + +class CatalogUpdateView(UpdateView): + form_class = SpecialistCatalogForm + model = SpecialistCatalog + template_name = 'admin/specialist/catalog_new.html' + success_url = reverse_lazy("catalog_all") + + def get_form(self, form_class): + form = super(CatalogUpdateView, self).get_form(form_class) + if self.object.type is 2: # city + form.fields['city'].widget.attrs['data-init-text'] = self.object.city.name + return form + + +class CatalogDeleteView(DeleteView): + model = SpecialistCatalog + template_name = 'admin/specialist/catalog_confirm_delete.html' + success_url = reverse_lazy("catalog_all") + + +# Feedback views + + +class FeedbackCreateView(CreateView): + form_class = FeedbackForm + model = Feedback + template_name = 'admin/specialist/feedback_new.html' + success_url = reverse_lazy("catalog_all") + + def get_initial(self): + catalog = get_object_or_404(SpecialistCatalog, pk=self.kwargs.get('catalog_pk')) + return {'catalog': catalog} + + +class FeedbackUpdateView(UpdateView): + form_class = FeedbackForm + model = Feedback + template_name = 'admin/specialist/feedback_new.html' + success_url = reverse_lazy("catalog_all") + + def get_initial(self): + catalog = get_object_or_404(SpecialistCatalog, pk=self.kwargs.get('catalog_pk')) + return {'catalog': catalog} + + +class FeedbackDeleteView(DeleteView): + model = Feedback + template_name = 'admin/specialist/feedback_confirm_delete.html' + success_url = reverse_lazy("catalog_all") + + +# ========= CLIENT VIEWS ============ + + +class CatalogDetailedView(SingleObjectMixin, FormView): + model = SpecialistCatalog + form_class = TranslationForm + template_name = "client/specialist_catalog/catalog_detailed.html" + success_url = reverse_lazy("service_thanks") + + def get_catalog_obj(self): + if self.kwargs.get('type') is "country": + try: + return self.model.objects.language().get(type=1, country__url=self.kwargs.get('slug')) + except self.model.DoesNotExist: + raise Http404 + else: + try: + return self.model.objects.language().get(type=2, city__url=self.kwargs.get('slug')) + except self.model.DoesNotExist: + raise Http404 + + def get_object(self, queryset=None): + obj = self.get_catalog_obj() + self.object = obj + return obj + + def get_context_data(self, **kwargs): + self.get_object() + context = super(CatalogDetailedView, self).get_context_data(**kwargs) + context['object'] = self.object + return context + + def form_valid(self, form): + order = form.save(commit=False) + order.save() + return HttpResponseRedirect(self.success_url) + + def get_initial(self): + obj = self.get_object() + init = {} + init['country'] = obj.country.name + if self.kwargs.get('type') is "city": + init['city'] = obj.city.name + return init + +class SpecCatalog(ListView): + model = SpecialistCatalog + template_name = 'client/specialist_catalog/catalog.html' + + def get_queryset(self): + + if self.kwargs.get('type') == "country": + ctype = _country + else: + ctype = _city + + qs = list(self.model.objects.language().select_related('country', 'city').filter(type=ctype)) + if ctype == _country: + result = sorted(qs, key=lambda x: x.country.name) + else: + result = sorted(qs, key=lambda x: x.city.name) + + return result + + def get_context_data(self, **kwargs): + context = super(SpecCatalog, self).get_context_data(**kwargs) + if self.kwargs.get('type') == "country": + context['title'] = _(u'Переводчики по странам') + else: + context['title'] = _(u'Переводчики по городам') + return context diff --git a/static/ckeditor/ckeditor/build-config.js b/static/ckeditor/ckeditor/build-config.js index 8a9004c8..9a930847 100644 --- a/static/ckeditor/ckeditor/build-config.js +++ b/static/ckeditor/ckeditor/build-config.js @@ -1,4 +1,4 @@ - + /** * @license Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.html or http://ckeditor.com/license diff --git a/static/ckeditor/ckeditor/lang/en.js b/static/ckeditor/ckeditor/lang/en.js index 1235ec20..4986aa54 100644 --- a/static/ckeditor/ckeditor/lang/en.js +++ b/static/ckeditor/ckeditor/lang/en.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/a11yhelp.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/a11yhelp.js index 4bf2d3c9..131153f4 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/a11yhelp.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/a11yhelp.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ar.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ar.js index 280f80a3..8ef366ca 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ar.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ar.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/bg.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/bg.js index 1950e9a4..d2fdc939 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/bg.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/bg.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ca.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ca.js index 2e269ef9..9d5674fe 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ca.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ca.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/cs.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/cs.js index 7b4b90f9..2c4be646 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/cs.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/cs.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/cy.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/cy.js index a5f07744..d0e887b4 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/cy.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/cy.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/da.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/da.js index fa0c807c..b1f0de3c 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/da.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/da.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/de.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/de.js index 70ecde16..44004a7c 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/de.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/de.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/el.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/el.js index cbf7e6d4..d95c73d5 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/el.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/el.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/en.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/en.js index 0124a3cf..04a47e4f 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/en.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/en.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/eo.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/eo.js index eed38987..e30b14e5 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/eo.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/eo.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/es.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/es.js index 877dc8ca..f6dcc565 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/es.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/es.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/et.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/et.js index 5e95b6ad..1b90907c 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/et.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/et.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/fa.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/fa.js index addcb1a2..50a45769 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/fa.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/fa.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/fi.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/fi.js index e0b75585..5e18e9ad 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/fi.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/fi.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/fr.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/fr.js index 1d2a58a2..9fffe798 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/fr.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/fr.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/gu.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/gu.js index 23ea2c41..9805b268 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/gu.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/gu.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/he.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/he.js index 34bceac0..4fc62304 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/he.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/he.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/hi.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/hi.js index 4a8f1792..cba4cc8a 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/hi.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/hi.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/hr.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/hr.js index b8ff14a1..7eafbbeb 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/hr.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/hr.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/hu.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/hu.js index f3bd161e..bb6999f7 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/hu.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/hu.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/it.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/it.js index e734f7dc..58de938f 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/it.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/it.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ja.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ja.js index 28cd8004..311a780c 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ja.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ja.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/km.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/km.js index 0af2f59a..23623f6b 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/km.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/km.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ku.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ku.js index f9f2d66b..6f52270d 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ku.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ku.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/lt.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/lt.js index 1cbb4285..b22bb18c 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/lt.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/lt.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/lv.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/lv.js index d93a754a..6aa311f3 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/lv.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/lv.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/mk.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/mk.js index 93531616..225ae9be 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/mk.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/mk.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/mn.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/mn.js index f9588d60..f53f8877 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/mn.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/mn.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/nb.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/nb.js index 7bb3de5b..863626ae 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/nb.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/nb.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/nl.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/nl.js index 1662a59c..749609da 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/nl.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/nl.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/no.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/no.js index dfb84937..e2e32b8c 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/no.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/no.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/pl.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/pl.js index 4ce90fe3..3ab4178e 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/pl.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/pl.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/pt-br.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/pt-br.js index 159fa598..74237d43 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/pt-br.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/pt-br.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/pt.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/pt.js index 08e50f87..7aaaa389 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/pt.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/pt.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ro.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ro.js index e4794d29..218023b9 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ro.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ro.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ru.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ru.js index cf0fce56..4d3c7adc 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ru.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ru.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/sk.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/sk.js index 1093ed9a..99245153 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/sk.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/sk.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/sl.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/sl.js index d6ad1c4b..a578d846 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/sl.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/sl.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/sv.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/sv.js index e156e198..a1aa4adb 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/sv.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/sv.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/th.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/th.js index afb8239b..903e538d 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/th.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/th.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/tr.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/tr.js index bef899b6..5c9f5784 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/tr.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/tr.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ug.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ug.js index c6c174f2..ef32f045 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ug.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/ug.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/uk.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/uk.js index 2451e8cc..4134a432 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/uk.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/uk.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/vi.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/vi.js index c7025b1b..147eaeb2 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/vi.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/vi.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/zh-cn.js b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/zh-cn.js index ef3a2dbb..dc9ee7a5 100644 --- a/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/zh-cn.js +++ b/static/ckeditor/ckeditor/plugins/a11yhelp/dialogs/lang/zh-cn.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/about/dialogs/about.js b/static/ckeditor/ckeditor/plugins/about/dialogs/about.js index 3d9156bf..ef9373bf 100644 --- a/static/ckeditor/ckeditor/plugins/about/dialogs/about.js +++ b/static/ckeditor/ckeditor/plugins/about/dialogs/about.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/clipboard/dialogs/paste.js b/static/ckeditor/ckeditor/plugins/clipboard/dialogs/paste.js index 8f94a715..bc7e9be1 100644 --- a/static/ckeditor/ckeditor/plugins/clipboard/dialogs/paste.js +++ b/static/ckeditor/ckeditor/plugins/clipboard/dialogs/paste.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/colordialog/dialogs/colordialog.js b/static/ckeditor/ckeditor/plugins/colordialog/dialogs/colordialog.js index 840cd4bb..31a92792 100644 --- a/static/ckeditor/ckeditor/plugins/colordialog/dialogs/colordialog.js +++ b/static/ckeditor/ckeditor/plugins/colordialog/dialogs/colordialog.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/dialog/dialogDefinition.js b/static/ckeditor/ckeditor/plugins/dialog/dialogDefinition.js index 2cb5d24b..6a84e65f 100644 --- a/static/ckeditor/ckeditor/plugins/dialog/dialogDefinition.js +++ b/static/ckeditor/ckeditor/plugins/dialog/dialogDefinition.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/div/dialogs/div.js b/static/ckeditor/ckeditor/plugins/div/dialogs/div.js index 0c26a56d..fbf1c4e7 100644 --- a/static/ckeditor/ckeditor/plugins/div/dialogs/div.js +++ b/static/ckeditor/ckeditor/plugins/div/dialogs/div.js @@ -1,4 +1,4 @@ -(function(){function p(a,k,o){if(!k.is||!k.getCustomData("block_processed"))k.is&&CKEDITOR.dom.element.setMarker(o,k,"block_processed",!0),a.push(k)}function n(a,k){function o(){this.foreach(function(d){if(/^(?!vbox|hbox)/.test(d.type)&&(d.setup||(d.setup=function(c){d.setValue(c.getAttribute(d.id)||"",1)}),!d.commit))d.commit=function(c){var a=this.getValue();"dir"==d.id&&c.getComputedStyle("direction")==a||(a?c.setAttribute(d.id,a):c.removeAttribute(d.id))}})}var n=function(){var d=CKEDITOR.tools.extend({}, +(function(){function p(a,k,o){if(!k.is||!k.getCustomData("block_processed"))k.is&&CKEDITOR.dom.element.setMarker(o,k,"block_processed",!0),a.push(k)}function n(a,k){function o(){this.foreach(function(d){if(/^(?!vbox|hbox)/.test(d.type)&&(d.setup||(d.setup=function(c){d.setValue(c.getAttribute(d.id)||"",1)}),!d.commit))d.commit=function(c){var a=this.getValue();"dir"==d.id&&c.getComputedStyle("direction")==a||(a?c.setAttribute(d.id,a):c.removeAttribute(d.id))}})}var n=function(){var d=CKEDITOR.tools.extend({}, CKEDITOR.dtd.$blockLimit);a.config.div_wrapTable&&(delete d.td,delete d.th);return d}(),q=CKEDITOR.dtd.div,l={},m=[];return{title:a.lang.div.title,minWidth:400,minHeight:165,contents:[{id:"info",label:a.lang.common.generalTab,title:a.lang.common.generalTab,elements:[{type:"hbox",widths:["50%","50%"],children:[{id:"elementStyle",type:"select",style:"width: 100%;",label:a.lang.div.styleSelectLabel,"default":"",items:[[a.lang.common.notSet,""]],onChange:function(){var d=["info:elementStyle","info:class", "advanced:dir","advanced:style"],c=this.getDialog(),h=c._element&&c._element.clone()||new CKEDITOR.dom.element("div",a.document);this.commit(h,!0);for(var d=[].concat(d),b=d.length,i,e=0;e=f.indexOf("?")?"?":"&"),f=f.replace("#","%23");if(null!==b.maxWidth&&("undefined"===typeof b.params.maxwidth||null===b.params.maxwidth))b.params.maxwidth=b.maxWidth;if(null!==b.maxHeight&&("undefined"===typeof b.params.maxheight||null===b.params.maxheight))b.params.maxheight=b.maxHeight;for(g in b.params)g!= +(function(a){function n(b,a){a=a?a:"";return b?n(--b,"0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz".charAt(Math.floor(60*Math.random()))+a):a}function p(b,a){var f=b.apiendpoint,d="",g,f=f+(0>=f.indexOf("?")?"?":"&"),f=f.replace("#","%23");if(null!==b.maxWidth&&("undefined"===typeof b.params.maxwidth||null===b.params.maxwidth))b.params.maxwidth=b.maxWidth;if(null!==b.maxHeight&&("undefined"===typeof b.params.maxheight||null===b.params.maxheight))b.params.maxheight=b.maxHeight;for(g in b.params)g!= b.callbackparameter&&null!==b.params[g]&&(d+="&"+escape(g)+"="+b.params[g]);f+="format="+b.format+"&url="+escape(a)+d;"json"!=b.dataType&&(f+="&"+b.callbackparameter+"=?");return f}function m(b,k,f){a("#jqoembeddata").data(k,b.code);l.beforeEmbed.call(f,b);l.onEmbed.call(f,b);l.afterEmbed.call(f,b)}function o(b,k,f){if(void 0!=a("#jqoembeddata").data(k)&&"iframe"!=f.embedtag.tag){var d={code:a("#jqoembeddata").data(k)};m(d,k,b)}else if(f.yql){var d=f.yql.from||"htmlstring",g=f.yql.url?f.yql.url(k): k,e="SELECT * FROM "+d+' WHERE url="'+g+'" and '+(/html/.test(d)?"xpath":"itemPath")+"='"+(f.yql.xpath||"/")+"'";"html"==d&&(e+=" and compat='html5'");d=a.extend({url:"http://query.yahooapis.com/v1/public/yql",dataType:"jsonp",data:{q:e,format:"json",env:"store://datatables.org/alltableswithkeys",callback:"?"},success:function(c){if(f.yql.xpath&&"//meta|//title|//link"==f.yql.xpath){var e={};null==c.query.results&&(c.query.results={meta:[]});for(var d=0,h=c.query.results.meta.length;d=f.indexOf("?")?"?":"&"),f=f.replace("#","%23");if(null!==b.maxWidth&&("undefined"===typeof b.params.maxwidth||null===b.params.maxwidth))b.params.maxwidth=b.maxWidth;if(null!==b.maxHeight&&("undefined"===typeof b.params.maxheight||null===b.params.maxheight))b.params.maxheight=b.maxHeight;for(g in b.params)g!= +(function(a){function n(b,a){a=a?a:"";return b?n(--b,"0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz".charAt(Math.floor(60*Math.random()))+a):a}function p(b,a){var f=b.apiendpoint,d="",g,f=f+(0>=f.indexOf("?")?"?":"&"),f=f.replace("#","%23");if(null!==b.maxWidth&&("undefined"===typeof b.params.maxwidth||null===b.params.maxwidth))b.params.maxwidth=b.maxWidth;if(null!==b.maxHeight&&("undefined"===typeof b.params.maxheight||null===b.params.maxheight))b.params.maxheight=b.maxHeight;for(g in b.params)g!= b.callbackparameter&&null!==b.params[g]&&(d+="&"+escape(g)+"="+b.params[g]);f+="format="+b.format+"&url="+escape(a)+d;"json"!=b.dataType&&(f+="&"+b.callbackparameter+"=?");return f}function m(b,k,f){a("#jqoembeddata").data(k,b.code);l.beforeEmbed.call(f,b);l.onEmbed.call(f,b);l.afterEmbed.call(f,b)}function o(b,k,f){if(void 0!=a("#jqoembeddata").data(k)&&"iframe"!=f.embedtag.tag){var d={code:a("#jqoembeddata").data(k)};m(d,k,b)}else if(f.yql){var d=f.yql.from||"htmlstring",g=f.yql.url?f.yql.url(k): k,e="SELECT * FROM "+d+' WHERE url="'+g+'" and '+(/html/.test(d)?"xpath":"itemPath")+"='"+(f.yql.xpath||"/")+"'";"html"==d&&(e+=" and compat='html5'");d=a.extend({url:"http://query.yahooapis.com/v1/public/yql",dataType:"jsonp",data:{q:e,format:"json",env:"store://datatables.org/alltableswithkeys",callback:"?"},success:function(c){if(f.yql.xpath&&"//meta|//title|//link"==f.yql.xpath){var e={};null==c.query.results&&(c.query.results={meta:[]});for(var d=0,h=c.query.results.meta.length;d=g)for(j||(h.push(''),j=!0);g<=a;){0==f&&h.push("");for(var e=!0,q=f;q"+l:">")+n+''+o+"");h.push("")}else{f=q;e=!1; break}if(e)f=0,h.push("");else break}}if(0!=f){for(g=f;g ");h.push("")}j?(h[0]=255':"
",h.push("
"),c=h.join(""),b.getElement().setHtml(c)):b.getElement().setHtml("
No valid range(s) defined...
")}else b.getElement().setHtml("
No range defined...
")}function t(a){a=a.toString(16).toUpperCase();return 1>a.length?eval('"\\u0000"'):2>a.length?eval('"\\u000'+a+'"'):3>a.length? diff --git a/static/ckeditor/ckeditor/plugins/table/dialogs/table.js b/static/ckeditor/ckeditor/plugins/table/dialogs/table.js index 01d9e38c..77d3a99d 100644 --- a/static/ckeditor/ckeditor/plugins/table/dialogs/table.js +++ b/static/ckeditor/ckeditor/plugins/table/dialogs/table.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/tabletools/dialogs/tableCell.js b/static/ckeditor/ckeditor/plugins/tabletools/dialogs/tableCell.js index 2c4e865b..930be031 100644 --- a/static/ckeditor/ckeditor/plugins/tabletools/dialogs/tableCell.js +++ b/static/ckeditor/ckeditor/plugins/tabletools/dialogs/tableCell.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/templates/dialogs/templates.js b/static/ckeditor/ckeditor/plugins/templates/dialogs/templates.js index 390fdb61..ae5dfc20 100644 --- a/static/ckeditor/ckeditor/plugins/templates/dialogs/templates.js +++ b/static/ckeditor/ckeditor/plugins/templates/dialogs/templates.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/templates/templates/default.js b/static/ckeditor/ckeditor/plugins/templates/templates/default.js index 51a4d9a6..b27f4782 100644 --- a/static/ckeditor/ckeditor/plugins/templates/templates/default.js +++ b/static/ckeditor/ckeditor/plugins/templates/templates/default.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/plugins/uploadcare/config.js b/static/ckeditor/ckeditor/plugins/uploadcare/config.js index 6d21c974..417041e4 100644 --- a/static/ckeditor/ckeditor/plugins/uploadcare/config.js +++ b/static/ckeditor/ckeditor/plugins/uploadcare/config.js @@ -1 +1 @@ -var UPLOADCARE_PUBLIC_KEY="demopublickey"; \ No newline at end of file +var UPLOADCARE_PUBLIC_KEY="demopublickey"; \ No newline at end of file diff --git a/static/ckeditor/ckeditor/plugins/wsc/dialogs/wsc.js b/static/ckeditor/ckeditor/plugins/wsc/dialogs/wsc.js index 6b39b006..294f11fe 100644 --- a/static/ckeditor/ckeditor/plugins/wsc/dialogs/wsc.js +++ b/static/ckeditor/ckeditor/plugins/wsc/dialogs/wsc.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2012, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/samples/assets/uilanguages/languages.js b/static/ckeditor/ckeditor/samples/assets/uilanguages/languages.js index 1b705f18..d07a0dac 100644 --- a/static/ckeditor/ckeditor/samples/assets/uilanguages/languages.js +++ b/static/ckeditor/ckeditor/samples/assets/uilanguages/languages.js @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/samples/plugins/dialog/assets/my_dialog.js b/static/ckeditor/ckeditor/samples/plugins/dialog/assets/my_dialog.js index e93c2ca3..73ff6bdd 100644 --- a/static/ckeditor/ckeditor/samples/plugins/dialog/assets/my_dialog.js +++ b/static/ckeditor/ckeditor/samples/plugins/dialog/assets/my_dialog.js @@ -1,4 +1,4 @@ -/** +/** * Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/samples/plugins/htmlwriter/assets/outputforflash/swfobject.js b/static/ckeditor/ckeditor/samples/plugins/htmlwriter/assets/outputforflash/swfobject.js index 95fdf0a7..76f37846 100644 --- a/static/ckeditor/ckeditor/samples/plugins/htmlwriter/assets/outputforflash/swfobject.js +++ b/static/ckeditor/ckeditor/samples/plugins/htmlwriter/assets/outputforflash/swfobject.js @@ -1,4 +1,4 @@ -var swfobject=function(){function u(){if(!s){try{var a=d.getElementsByTagName("body")[0].appendChild(d.createElement("span"));a.parentNode.removeChild(a)}catch(b){return}s=!0;for(var a=x.length,c=0;cf){f++;setTimeout(arguments.callee,10);return}a.removeChild(b);c=null;D()})()}else D()}function D(){var a=p.length;if(0e.wk))t(c,!0),f&&(g.success=!0,g.ref=E(c),f(g));else if(p[b].expressInstall&&F()){g={};g.data=p[b].expressInstall;g.width=d.getAttribute("width")||"0";g.height=d.getAttribute("height")||"0";d.getAttribute("class")&&(g.styleclass=d.getAttribute("class"));d.getAttribute("align")&&(g.align=d.getAttribute("align"));for(var h={},d=d.getElementsByTagName("param"),j=d.length,k=0;ke.wk)}function G(a,b,c,f){A=!0;H=f||null;N={success:!1,id:c};var g=n(c);if(g){"OBJECT"==g.nodeName?(w=I(g),B=null):(w=g,B=c);a.id= diff --git a/static/ckeditor/ckeditor/samples/sample.js b/static/ckeditor/ckeditor/samples/sample.js index 79c76796..17332ada 100644 --- a/static/ckeditor/ckeditor/samples/sample.js +++ b/static/ckeditor/ckeditor/samples/sample.js @@ -1,4 +1,4 @@ -/** +/** * Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/ckeditor/ckeditor/styles.js b/static/ckeditor/ckeditor/styles.js index 9cd1c13a..6bf8cb1a 100644 --- a/static/ckeditor/ckeditor/styles.js +++ b/static/ckeditor/ckeditor/styles.js @@ -1,4 +1,4 @@ -/** +/** * Copyright (c) 2003-2013, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.html or http://ckeditor.com/license */ diff --git a/static/client b/static/client deleted file mode 120000 index 52754f3f..00000000 --- a/static/client +++ /dev/null @@ -1 +0,0 @@ -/home/www/proj/templates/client/static_client \ No newline at end of file diff --git a/static/client b/static/client new file mode 100644 index 00000000..52754f3f --- /dev/null +++ b/static/client @@ -0,0 +1 @@ +/home/www/proj/templates/client/static_client \ No newline at end of file diff --git a/static/custom_js/place_city_ajax.js b/static/custom_js/place_city_ajax.js index 716ff370..12cbd744 100644 --- a/static/custom_js/place_city_ajax.js +++ b/static/custom_js/place_city_ajax.js @@ -14,6 +14,5 @@ $('#id_city').attr('disabled', false); }); - }); }); diff --git a/static/custom_js/specialist.js b/static/custom_js/specialist.js new file mode 100644 index 00000000..560d85a8 --- /dev/null +++ b/static/custom_js/specialist.js @@ -0,0 +1,93 @@ +/** + * Created by dev on 07.09.2015. + */ +$(document).ready(function () { + $('select').select2({ + width: 'element', + allowClear: true + }); + + $('#id_country').change(function () { + $.get( + "/admin/ajax_city/", {'id': $(this).val()}, function (j) { + + $('#id_city').html(j); + $('#id_city').attr('disabled', false); + + }); + }); + + + $('#id_city').select2({ + placeholder: "Город", + width: 300, + ajax: { + + url: "/admin/city/search/", + dataType: "json", + quietMillis: 200, + + data: function (term, page, country) { + var country = $('#id_country').val(); + return { + term: term, + page: page, + country: country + }; + }, + + 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 id = $(element).val(); + var text = $(element).attr('data-init-text'); + callback({id: id, text: text}); + + } + + }); + + + // displaying uploaded photo + + function handleFileSelect(evt) { + var files = evt.target.files; // FileList object + + // Loop through the FileList and render image files as thumbnails. + for (var i = 0, f; f = files[i]; i++) { + + // Only process image files. + if (!f.type.match('image.*')) { + continue; + } + + var reader = new FileReader(); + + // Closure to capture the file information. + + reader.onload = (function (theFile) { + return function (e) { + document.getElementById('list').innerHTML = [''].join(''); + }; + })(f); + + + // Read in the image file as a data URL. + reader.readAsDataURL(f); + } + } + + document.getElementById('id_photo').addEventListener('change', handleFileSelect, false); + document.getElementById('id_logo').addEventListener('change', handleFileSelect, false); + console.log("hello from new specialist view.js"); +}); \ No newline at end of file diff --git a/static/custom_js/specialist_catalog.js b/static/custom_js/specialist_catalog.js new file mode 100644 index 00000000..cdc3ef55 --- /dev/null +++ b/static/custom_js/specialist_catalog.js @@ -0,0 +1,120 @@ +/** + * Created by dev on 07.09.2015. + */ +$(document).ready(function () { + $('select').select2({ + width: 'element', + allowClear: true + }); + + $('#id_country').change(function () { + $.get( + "/admin/ajax_city/", {'id': $(this).val()}, function (j) { + + $('#id_city').html(j); + $('#id_city').attr('disabled', false); + + }); + }); + + + $('#id_city').select2({ + placeholder: "Город", + width: 300, + ajax: { + + url: "/admin/city/search/", + dataType: "json", + quietMillis: 200, + + data: function (term, page, country) { + var country = $('#id_country').val(); + return { + term: term, + page: page, + country: country + }; + }, + + 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 id = $(element).val(); + var text = $(element).attr('data-init-text'); + callback({id: id, text: text}); + + } + + }); + + + // displaying uploaded photo + + function handleFileSelect1(evt) { + var files = evt.target.files; // FileList object + + // Loop through the FileList and render image files as thumbnails. + for (var i = 0, f; f = files[i]; i++) { + + // Only process image files. + if (!f.type.match('image.*')) { + continue; + } + + var reader = new FileReader(); + + // Closure to capture the file information. + + reader.onload = (function (theFile) { + return function (e) { + document.getElementById('list_picture').innerHTML = [''].join(''); + }; + })(f); + + + // Read in the image file as a data URL. + reader.readAsDataURL(f); + } + } + function handleFileSelect2(evt) { + var files = evt.target.files; // FileList object + + // Loop through the FileList and render image files as thumbnails. + for (var i = 0, f; f = files[i]; i++) { + + // Only process image files. + if (!f.type.match('image.*')) { + continue; + } + + var reader = new FileReader(); + + // Closure to capture the file information. + + reader.onload = (function (theFile) { + return function (e) { + document.getElementById('list_logo').innerHTML = [''].join(''); + }; + })(f); + + + // Read in the image file as a data URL. + reader.readAsDataURL(f); + } + } + + document.getElementById('id_place_photo').addEventListener('change', handleFileSelect1, false); + document.getElementById('id_logo_preview').addEventListener('change', handleFileSelect2, false); + console.log("hello from new catalog view.js"); +}); \ No newline at end of file diff --git a/static/custom_js/wizard.js b/static/custom_js/wizard.js new file mode 100644 index 00000000..796e2b8f --- /dev/null +++ b/static/custom_js/wizard.js @@ -0,0 +1,167 @@ +/** + * Created by dev on 07.09.2015. + */ +$(document).ready(function () { + $('select').select2({ + width: 'element', + allowClear: true + }); + + $('#id_country').change(function () { + $.get( + "/admin/ajax_city/", {'id': $(this).val()}, function (j) { + + $('#id_city').html(j); + $('#id_city').attr('disabled', false); + + }); + }); + $('#id_place').select2({ + placeholder:"Место проведения", + widht: 400 + }); + + $('#id_city').select2({ + placeholder: "Город", + width: 300, + ajax: { + + url: "/admin/city/search/", + dataType: "json", + quietMillis: 200, + + data: function (term, page, country) { + var country = $('#id_country').val() + return { + term: term, + page: page, + country: country + }; + }, + + 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 id = $(element).val(); + var text = $(element).attr('data-init-text'); + callback({id: id, text: text}); + + } + + }); + $('#id_0-periodic').select2({ + placeholder: "Периодичность", + width: '350px' + }); + + + $('#id_tag').select2({ + placeholder: "Теги", + width: '350px', + multiple: true, + ajax: { + + url: "/admin/theme/tag/search/", + dataType: "json", + quietMillis: 200, + multiple: true, + + data: function (term, page, theme) { + var theme = $('#id_theme').serialize().replace(/0-theme/g, 'theme'); + return { + term: term, + page: page, + theme: theme + }; + }, + + results: function (data) { + var results = []; + $.each(data, function (index, item) { + results.push({ + id: item.id, + text: item.label + }); + }); + return {results: results}; + } + }, + initSelection: function (element, callback) { + var data = []; + $(element.val().split(",")).each(function (i) { + var item = this.split(':'); + data.push({ + id: item[0], + text: item[1] + }); + }); + callback(data); + + } + + }); + // end selects + /* + */ + // theme change + + $('#id_theme').change(function () { + $.get( + "/admin/ajax_tag/", {'id': $(this).serialize().replace(/0-theme/g, 'theme')}, function (data) { + var optionValues = []; + var getValues = []; + var selectedValues = []; + //push values sended from server in array + $.each(data, function (i, elem) { + getValues.push(elem[0].toString()) + }); + //delete options if they aren't in getvalues + //otherwise push it in array + //also push in array already selected values + $('#id_tag option').each(function () { + var check = $.inArray($(this), getValues); + if ($(this).is(':selected')) { + selectedValues.push($(this).val()) + } + if (check == -1) { + $(this).remove() + } + else { + optionValues.push($(this).val()); + } + }); + //generate new options + //old options unchanged + var html = ''; + $.each(data, function (i, elem) { + var check = $.inArray(elem[0].toString(), optionValues); + + if (check == -1) { + html += ''; + } + }); + $('#id_tag').append(html); + //select previous selected values + $('#id_tag option').each(function () { + var check = $.inArray($(this).val(), selectedValues) + if (check != -1) { + $(this).attr('selected', 'selected'); + } + }); + });//end get + });//end change + console.log("hello from wizard.js"); + }); \ No newline at end of file diff --git a/static/js/datetimepicker/js/locales/bootstrap-datetimepicker.lt.js b/static/js/datetimepicker/js/locales/bootstrap-datetimepicker.lt.js index 8018a70e..a639f6eb 100644 --- a/static/js/datetimepicker/js/locales/bootstrap-datetimepicker.lt.js +++ b/static/js/datetimepicker/js/locales/bootstrap-datetimepicker.lt.js @@ -1,4 +1,4 @@ -/** +/** * Lithuanian translation for bootstrap-datetimepicker * Šarūnas Gliebus */ diff --git a/templates/admin/expobanner/main_list.html b/templates/admin/expobanner/main_list.html index 0175e392..a06a2411 100644 --- a/templates/admin/expobanner/main_list.html +++ b/templates/admin/expobanner/main_list.html @@ -1,4 +1,4 @@ -{% extends 'base.html' %} +{% extends 'admin/base.html' %} {% block body %} @@ -8,7 +8,14 @@
{% block list_table %} - Добавить выставку + +
+
+ Только опубликование +
+
@@ -36,5 +43,13 @@ {# pagination #} {% include 'admin/includes/admin_pagination.html' with page_obj=object_list %} - + {% endblock %} \ No newline at end of file diff --git a/templates/admin/expobanner/main_stat.html b/templates/admin/expobanner/main_stat.html index 1e1a5bb6..6c593bb7 100644 --- a/templates/admin/expobanner/main_stat.html +++ b/templates/admin/expobanner/main_stat.html @@ -1,4 +1,4 @@ -{% extends 'base.html' %} +{% extends 'admin/base.html' %} {% load static %} {% block scripts %} @@ -27,6 +27,14 @@ + + + + + + + + {% with stats=stats %} {% for stat in stats %} diff --git a/templates/admin/expobanner/paid_list.html b/templates/admin/expobanner/paid_list.html index 81402128..f4996058 100644 --- a/templates/admin/expobanner/paid_list.html +++ b/templates/admin/expobanner/paid_list.html @@ -8,8 +8,13 @@
{% block list_table %} - Добавить выставку -
Всего{{ all.views }}{{ all.clicks }}{{ all.unique_views}}{{ all.unique_clicks }}
+ Добавить выставку +
+
+ Только опубликование + +
+
@@ -34,5 +39,13 @@ {# pagination #} {% include 'admin/includes/admin_pagination.html' with page_obj=object_list %} - + {% endblock %} \ No newline at end of file diff --git a/templates/admin/expobanner/paid_stat.html b/templates/admin/expobanner/paid_stat.html index b47791c5..86bbc620 100644 --- a/templates/admin/expobanner/paid_stat.html +++ b/templates/admin/expobanner/paid_stat.html @@ -27,6 +27,13 @@ + + + + + + + {% with stats=object.paidstat_set.all %} {% for stat in stats %} diff --git a/templates/admin/expobanner/top_list.html b/templates/admin/expobanner/top_list.html index 78642de7..13110d32 100644 --- a/templates/admin/expobanner/top_list.html +++ b/templates/admin/expobanner/top_list.html @@ -9,6 +9,11 @@
{% block list_table %} Добавить выставку +
+
+ Только активние + +
Выставка
За весь период{{ all.official }}{{ all.ticket }}{{ all.participation}}{{ all.catalog }}
@@ -32,5 +37,13 @@ {# pagination #} {% include 'admin/includes/admin_pagination.html' with page_obj=object_list %} - + {% endblock %} \ No newline at end of file diff --git a/templates/admin/includes/admin_nav.html b/templates/admin/includes/admin_nav.html index 068e0067..25226d51 100644 --- a/templates/admin/includes/admin_nav.html +++ b/templates/admin/includes/admin_nav.html @@ -29,11 +29,7 @@ Пользователи @@ -46,7 +42,6 @@
  • Тематики
  • Теги
  • Услуги
  • -
  • Настройки
  • Главная страница
  • Мета
  • @@ -61,9 +56,8 @@
    + + + + + + + + + + + {% for item in object_list %} + + + + + + + + + {% endfor %} + +
    Заголовок{% if request.path == "/admin/specialist_catalog/catalog/city/" %}Город{% elif request.path == "/admin/specialist_catalog/catalog/country/" %}Страна{% else %}Страна/Город{% endif %}Link 
    {{ item.title }}{% if item.type == 1%}{{ item.country.name }}{% else %}{{ item.city.name }}{% endif %}на сайте + + Изменить + + + + Удалить + +
    + + Добавить +
    + {% include 'admin/includes/admin_pagination.html' %} + + +{% endblock %} \ No newline at end of file diff --git a/templates/admin/specialist/catalog_confirm_delete.html b/templates/admin/specialist/catalog_confirm_delete.html new file mode 100644 index 00000000..6dd1ae8e --- /dev/null +++ b/templates/admin/specialist/catalog_confirm_delete.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% block sidebar %}{% endblock %} +{% block body %} +
    {% csrf_token %} +
    +

    Вы точно хотите удалить "{{ object.title }}" ?

    + + Нет +
    +
    +{% endblock %} \ No newline at end of file diff --git a/templates/admin/specialist/catalog_new.html b/templates/admin/specialist/catalog_new.html new file mode 100644 index 00000000..f938184c --- /dev/null +++ b/templates/admin/specialist/catalog_new.html @@ -0,0 +1,195 @@ +{% extends 'base.html' %} +{% load thumbnail %} +{% load static %} +{# Displays article form #} + + {% block scripts %} + + {# selects for city and country #} + + + + + {% endblock %} + +{% block body %} +
    {% csrf_token %} +
    +
    +
    +

    Добавление каталога специалистов(переводчиков)

    +
    +
    + {# title #} +
    + +
    + {{ form.title }} + {{ form.title.errors }} +
    +
    + {# main_descr #} +
    + +
    + {{ form.main_descr }} + {{ form.main_descr.errors }} +
    +
    + + {# benefits #} +
    + +
    + {{ form.benefits }} + {{ form.benefits.errors }} +
    +
    + {# big_cities #} +
    + +
    + {{ form.big_cities }} + {{ form.big_cities.errors }} +
    +
    + + {# price #} +
    + +
    + {{ form.price }}{{ form.currency.label }}{{ form.currency }} + {{ form.price.errors }} +
    +
    + + {# type #} +
    + +
    + {{ form.type }} + {{ form.type.errors }} +
    +
    + + {# country #} +
    + +
    + {{ form.country }} + {{ form.country.errors }} +
    +
    + {# city #} +
    + +
    + {{ form.city }} + {{ form.city.errors }} +
    +
    + + {# specialists #} +
    + +
    + {{ form.specialists }}Довавить + {{ form.specialists.errors }} +
    +
    + {# logo_preview #} +
    + +
    + {{ form.logo_preview }} + {{ form.logo_preview.errors }} +
    +
    + {# place_photo #} +
    + +
    + {{ form.place_photo }} + {{ form.place_photo.errors }} +
    +
    + +
    +
    + +
    + + + + Вернуться +
    +
    +
    + + +
    +
    +

    Отзывы для текущего каталога

    +
    +
    + {% if object.feedback_set.all %} + {% with object.feedback_set.all as feedbacks %} + + + + + + + + + + + + + {% for item in feedbacks %} + + + + + + + + + + + {% endfor %} + +
    ЛоготипИмяКомпанияТекст 
    + {% thumbnail item.logo "100x100" crop="center" as im %} + + {% endthumbnail %}{{ item.name }}{{ item.company }}{{ item.text }} + + Изменить + + + + Удалить + +
    + + Хочу еще один + {% endwith %} + {% elif object.id %} + Отзывов еще нет, + + Добавить + {% endif %} +
    + + +
    + + + +{% endblock %} diff --git a/templates/admin/specialist/feedback_all.html b/templates/admin/specialist/feedback_all.html new file mode 100644 index 00000000..2d40605f --- /dev/null +++ b/templates/admin/specialist/feedback_all.html @@ -0,0 +1,62 @@ +{% extends 'base.html' %} +{% load thumbnail %} +{% block body %} +
    +
    +

    Отзывы для %(calatolog)

    +
    +
    + + + + + + + + + + + + + {% for item in object_list %} + + + + + + + + + + + {% endfor %} + +
    Логотип ИмяКомпанияТекст 
    + {% thumbnail item.logo "100x100" crop="center" as im %} + + {% endthumbnail %}{{ item.name }}{{ item.company }}{{ item.text }} + + Изменить + + + + Удалить + +
    + + Хочу еще один +
    + + +
    +{% endblock %} \ No newline at end of file diff --git a/templates/admin/specialist/feedback_confirm_delete.html b/templates/admin/specialist/feedback_confirm_delete.html new file mode 100644 index 00000000..2314e117 --- /dev/null +++ b/templates/admin/specialist/feedback_confirm_delete.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% block sidebar %}{% endblock %} +{% block body %} +
    {% csrf_token %} +
    +

    Вы точно хотите удалить "{{ object.name }}" ?

    + + Нет +
    +
    +{% endblock %} \ No newline at end of file diff --git a/templates/admin/specialist/feedback_new.html b/templates/admin/specialist/feedback_new.html new file mode 100644 index 00000000..404651b1 --- /dev/null +++ b/templates/admin/specialist/feedback_new.html @@ -0,0 +1,79 @@ +{% extends 'base.html' %} +{% load static %} +{# Displays article form #} + + {% block scripts %} + {# selects for city and country #} + + + + + {% endblock %} + +{% block body %} +
    {% csrf_token %} +
    +
    +
    +

    Добавление отз ва

    +
    +
    + {# name #} +
    + +
    + {{ form.name }} + {{ form.name.errors }} +
    +
    + {# company #} +
    + +
    + {{ form.company }} + {{ form.company.errors }} +
    +
    + {# text #} +
    + +
    + {{ form.text }} + {{ form.text.errors }} +
    +
    + {# catalog #} +
    + +
    + {{ form.catalog }} + {{ form.catalog.errors }} +
    +
    + {# logo #} +
    + +
    + {{ form.logo }} + {{ form.logo.errors }} +
    +
    + +
    +
    + +
    + + + +
    +
    +
    + +{% endblock %} diff --git a/templates/admin/specialist/specialist_all.html b/templates/admin/specialist/specialist_all.html new file mode 100644 index 00000000..df69fa63 --- /dev/null +++ b/templates/admin/specialist/specialist_all.html @@ -0,0 +1,76 @@ +{% extends 'base.html' %} +{% load thumbnail %} +{% block body %} +
    +
    +

    Поиск

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

    Список специалистов(переводчиков)

    +
    +
    + + + + + + + + + + + + + {% for item in object_list %} + + + + + + + + + + + {% endfor %} + +
    Фото ИмяГородЯзыки 
    + {% thumbnail item.photo "100x100" crop="center" as im %} + + {% endthumbnail %}{{ item.name }}{{ item.city.name }}{{ item.languages }} + + Изменить + + + + Удалить + +
    + + Хочу еще +
    + + +
    +{% endblock %} \ No newline at end of file diff --git a/templates/admin/specialist/specialist_confirm_delete.html b/templates/admin/specialist/specialist_confirm_delete.html new file mode 100644 index 00000000..4cb4b98c --- /dev/null +++ b/templates/admin/specialist/specialist_confirm_delete.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% block sidebar %}{% endblock %} +{% block body %} +
    {% csrf_token %} +
    +

    Вы точно хотите удалить "{{ object.name }}" ?

    + + Нет +
    +
    +{% endblock %} \ No newline at end of file diff --git a/templates/admin/specialist/specialist_new.html b/templates/admin/specialist/specialist_new.html new file mode 100644 index 00000000..7835b82c --- /dev/null +++ b/templates/admin/specialist/specialist_new.html @@ -0,0 +1,79 @@ +{% extends 'base.html' %} +{% load static %} +{# Displays article form #} + + {% block scripts %} + {# selects for city and country #} + + + + + {% endblock %} + +{% block body %} +
    {% csrf_token %} +
    +
    +
    +

    Добавление специалиста(переводчика)

    +
    +
    + {# name #} +
    + +
    + {{ form.name }} + {{ form.name.errors }} +
    +
    + {# languages #} +
    + +
    + {{ form.languages }} + {{ form.languages.errors }} +
    +
    + {# country #} +
    + +
    + {{ form.country }} + {{ form.country.errors }} +
    +
    + {# city #} +
    + +
    + {{ form.city }} + {{ form.city.errors }} +
    +
    + {# photo #} +
    + +
    + {{ form.photo }} + {{ form.photo.errors }} +
    +
    + +
    +
    + +
    + + + +
    +
    +
    + +{% endblock %} diff --git a/templates/client/404.html b/templates/client/404.html index bded0e78..27dc338f 100644 --- a/templates/client/404.html +++ b/templates/client/404.html @@ -1,17 +1,18 @@ {% extends 'base_catalog.html' %} +{% load i18n %} {% block content_list %}
    -

    Запрашиваемая страница не найдена

    +

    {% trans 'Запрашиваемая страница не найдена' %}

    404: -

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

    +

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


    -

    Каталог выставок

    +

    {% trans 'Каталог выставок' %}


    -

    Каталог конференций

    +

    {% trans 'Каталог конференций' %}

      {% for item in conf_themes %}
    • {{ item.name }} ({{ item.conference_count }})
    • diff --git a/templates/client/404_test.html b/templates/client/404_test.html new file mode 100644 index 00000000..bded0e78 --- /dev/null +++ b/templates/client/404_test.html @@ -0,0 +1,31 @@ +{% extends 'base_catalog.html' %} + +{% block content_list %} + +
      +

      Запрашиваемая страница не найдена

      +
      +
      + 404: +

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

      +
      +
      +
      +

      Каталог выставок

      + +
      +
      +
      +

      Каталог конференций

      + +
      +
      +{% endblock %} \ No newline at end of file diff --git a/templates/client/accounts/calendar.html b/templates/client/accounts/calendar.html index 261d1bfd..ad9766c6 100644 --- a/templates/client/accounts/calendar.html +++ b/templates/client/accounts/calendar.html @@ -28,16 +28,18 @@ {% if events|length > 0 %}
      {{ days.15|date:"F"}}’{{ days.15|date:"y"}}
      - {% include 'includes/accounts/calendar_list.html' with events=events %} + {% include 'client/includes/accounts/calendar_list.html' with events=events %}
      + {% endblock %} {% block scripts %} - + +++++++++++++++++++++++++++++++++++++++++++++++++++++++ {% endblock %} \ No newline at end of file diff --git a/templates/client/accounts/email_required.html b/templates/client/accounts/email_required.html index 24300f36..bcacaaeb 100644 --- a/templates/client/accounts/email_required.html +++ b/templates/client/accounts/email_required.html @@ -1,7 +1,7 @@ -{% extends 'client/blank.html' %} -{% block main_part %} -
      {% csrf_token %} - {{ form }} - -
      +{% extends 'client/blank.html' %} +{% block main_part %} +
      {% csrf_token %} + {{ form }} + +
      {% endblock %} \ No newline at end of file diff --git a/templates/client/accounts/fill_company.html b/templates/client/accounts/fill_company.html index c338e95d..e3208cdb 100644 --- a/templates/client/accounts/fill_company.html +++ b/templates/client/accounts/fill_company.html @@ -72,9 +72,9 @@
    - +
    - закрыть + {% trans 'закрыть' %} @@ -115,8 +115,8 @@ {% if spec_form.specialization.value %} {% trans 'редактировать' %} {% else %} - Добавить - + {% trans 'Добавить' %} + {% endif %}
    {% csrf_token %} @@ -130,10 +130,10 @@
    - +
    - закрыть + {% trans 'закрыть' %} @@ -151,8 +151,8 @@ {% if address_form.address_inf.value %} {% trans 'редактировать' %} {% else %} - Добавить - + {% trans 'Добавить' %} + {% endif %}
    {% csrf_token %} @@ -163,10 +163,10 @@
    - +
    - закрыть + {% trans 'закрыть' %} @@ -269,8 +269,8 @@ {% if phone_form.phone.value %} {% trans 'редактировать' %} {% else %} - Добавить - + {% trans 'Добавить' %} + {% endif %}
    {% csrf_token %} @@ -301,7 +301,7 @@ {% if email_form.email.value %} {% trans 'редактировать' %} {% else %} - Добавить + {% trans 'Добавить' %} {% endif %}
    diff --git a/templates/client/accounts/new_profile.html b/templates/client/accounts/new_profile.html index bf5d47bb..472b4f2d 100644 --- a/templates/client/accounts/new_profile.html +++ b/templates/client/accounts/new_profile.html @@ -46,8 +46,10 @@
    551
    + {% blocktrans %}

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

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

    + {% endblocktrans %}
    @@ -83,7 +85,7 @@
    - +
    {{ home_form.country }}
    @@ -99,11 +101,11 @@
    - +
    - закрыть + {% trans 'закрыть' %}
    @@ -159,8 +161,8 @@ {% if work_form.position.value and work_form.company.value %} {% trans 'редактировать' %} {% else %} - Указать - + {% trans 'Указать' %} + {% endif %}
    {% csrf_token %} @@ -191,12 +193,12 @@
    - редактировать профиль - завершить редактирование + {% trans 'редактировать профиль' %} + {% trans 'завершить редактирование' %}
    Добавить профили в соц.сетях: