# -*- coding: utf-8 -*- import hashlib import random from collections import namedtuple from datetime import date, datetime from conference.models import Conference from country.models import Country 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 exposition.models import Exposition from functions.custom_fields import MonthMultiSelectField from theme.models import Theme 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) 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) # 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'), } 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) 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')) 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')) 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) 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): """ 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)