# -*- coding: utf-8 -*- import hashlib import random from collections import namedtuple from datetime import date, datetime from django.conf import settings from django.contrib.sites.models import Site from django.db import models from django.db.models.signals import post_save from django.utils.translation import ugettext_lazy as _ from functions.custom_fields import MonthMultiSelectField from conference.models import Conference from country.models import Country from exposition.models import Exposition from theme.models import Theme from place_conference.models import PlaceConference from place_exposition.models import PlaceExposition from .managers import BannerGroupCached, BiasedManager, TopCached, URLCached from .mixins import StatMixin class URL(models.Model): """ Model for urls or regex urls that can be used in banners representation """ 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): """ place where banner can be show """ 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 Customer(models.Model): name = models.CharField(_(u'Название'), max_length=255) description = models.TextField(_(u'Дополнительная информация'), blank=True, null=True) created_at = models.DateTimeField(verbose_name=_('Created At'), auto_now_add=True) updated_at = models.DateTimeField(verbose_name=_('Updated At'), auto_now=True) def __unicode__(self): return u'{name}'.format(name=self.name) class Meta: ordering = ['name'] verbose_name = _(u'Заказчик') verbose_name_plural = _(u'Заказчики') class Banner(models.Model, StatMixin): """ Uses for store information about banners. Also can be used as tracked link """ objects = BiasedManager() customer = models.ForeignKey(Customer, verbose_name=_(u'Заказчик'), null=True, blank=True, help_text=_(u'Работает для всех баннеров кроме верхнего.'), ) 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=_(u'Частота показа'), default=1, null=True, blank=True, help_text=_(u'Задается в %. 20 будет соответствовать 20% показа банера из всех просмотров. Работает только для верхнего банера.'), # choices=[[i, i] for i in xrange(11)], ) urls = models.ManyToManyField(URL, related_name='url_banners', verbose_name=_('URLs'), null=True, blank=True) html = models.BooleanField(verbose_name=_('HTML?'), default=False) flash = models.BooleanField(verbose_name=_('Flash?'), default=False) 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) # password for clients 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 @property def key(self): 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, t): """ creating log by request """ log = { 'type': t, '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', '')[:255], } 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): """ store information about showing and clicking of banners """ 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, max_length=255) 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): """ store aggregated data of logs """ 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'), null=True, default=0) click = models.PositiveIntegerField(verbose_name=_('Clicks'), null=True, default=0) unique_click = models.PositiveIntegerField(verbose_name=_('Unique Views'), blank=True, null=True, default=0) unique_view = models.PositiveIntegerField(verbose_name=_('Unique Clicks'), null=True, default=0) updated_at = models.DateTimeField(auto_now=True, null=True) def __unicode__(self): return '%s - (%s)' % (self.banner, self.date) class Meta: ordering = ['-date'] class Paid(models.Model, StatMixin): """ store information about paid events """ expo = 1 conf = 2 kind = models.PositiveSmallIntegerField(verbose_name=_(u'Тип'), default=1, db_index=True) tickets = models.ForeignKey(Banner, related_name='paid_tickets') participation = models.ForeignKey(Banner, related_name='paid_participation', null=True) 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): model = Exposition if self.kind == self.expo else Conference try: return model.objects.get(paid_new_id=self.pk) except model.DoesNotExist: return None class PaidStat(models.Model): """ aggregated data of paid logs """ 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): """ store information about events in top """ YEARS = map( lambda x: (x, x), tuple(xrange(date.today().year - 1, date.today().year + 5)) ) 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'Страны')) cities = models.ManyToManyField('city.City', related_name='top_in_set', blank=True, null=True, verbose_name=_(u'Города')) months = MonthMultiSelectField(_(u'Топ месяца'), blank=True, null=True, default=None, max_length=255,) years = models.PositiveSmallIntegerField(_(u'Топ года'), choices=YEARS, blank=True, null=True, default=None) 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) base_catalog = models.BooleanField(_(u'Общий раздел'), blank=True, default=False) objects = models.Manager() cached = TopCached() class Meta: ordering = ['position'] def get_event(self): # if self.catalog: models = {'expo': [Exposition], 'conference': [Conference], 'places': [PlaceExposition, PlaceConference]} model_list = models.get(self.catalog) event = None for model in model_list: try: event = model.objects.get(top_id=self.pk) except model.DoesNotExist: pass return event class TopStat(models.Model): """ aggregated data of logs events in top """ 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): """ events on main page info """ 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: try: return self.conference_set.all()[0] except IndexError: return None def __unicode__(self): return self.get_event().url 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)