# -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 import copy from datetime import datetime from django.contrib.auth.models import User from django.db import models from django.db.models import Max from django.conf import settings from django.contrib.gis.utils import GeoIP import ox from ox.django.fields import DictField from ox.utils import json from itemlist.models import List, Position import text import managers import tasks class SessionData(models.Model): session_key = models.CharField(max_length=40, primary_key=True) user = models.ForeignKey(User, unique=True, null=True, blank=True, related_name='data') firstseen = models.DateTimeField(auto_now_add=True, db_index=True) lastseen = models.DateTimeField(default=datetime.now, db_index=True) username = models.CharField(max_length=255, null=True, db_index=True) level = models.IntegerField(default=0) timesseen = models.IntegerField(default=0) ip = models.CharField(max_length=255, null=True) useragent = models.CharField(max_length=255, null=True) windowsize = models.CharField(max_length=255, null=True) screensize = models.CharField(max_length=255, null=True) info = DictField(default={}) location = models.CharField(max_length=255, null=True) location_sort = models.CharField(max_length=255, null=True) system = models.CharField(max_length=255, null=True) browser = models.CharField(max_length=255, null=True) numberoflists = models.IntegerField(default=0, null=True) objects = managers.SessionDataManager() groupssort = models.CharField(default=None,blank=True,null=True, max_length=255) def __unicode__(self): return u"%s" % self.session_key def parse_useragent(self): if self.useragent: ua = ox.parse_useragent(self.useragent) self.browser = ua['browser']['string'].lower() self.system = ua['system']['string'].lower() if not self.browser: self.browser = None if not self.system: self.system = None if ua['robot']['name']: self.level = -1 def parse_data(self): self.parse_useragent() if self.ip: try: g = GeoIP() location = g.city(self.ip) if location: country = ox.get_country_name(location['country_code']) if location['city']: city = location['city'] if type(city) != unicode: city = city.decode('latin-1') self.location = u'%s, %s' % (city, country) self.location_sort = u'%s, %s' % (country, city) else: self.location_sort = self.location = country else: self.location_sort = self.location = None except: self.location_sort = self.location = None pass def save(self, *args, **kwargs): if self.user: self.username = self.user.username self.level = self.user.get_profile().level self.firstseen = self.user.date_joined self.groupssort = ''.join([g.name for g in self.user.groups.all()]) self.numberoflists = self.user.lists.count() else: self.groupssort = None super(SessionData, self).save(*args, **kwargs) @classmethod def get_or_create(cls, request): if not request.session.session_key: request.session.save() request.session.modified = True session_key = request.session.session_key assert session_key if request.user.is_authenticated(): cls.objects.filter(user=request.user).update(session_key=session_key) data, created = cls.objects.get_or_create(session_key=session_key) if request.user.is_authenticated(): data.user = request.user data.ip = request.META['REMOTE_ADDR'] if data.ip.startswith('::ffff:'): data.ip = data.ip[len('::ffff:'):] data.useragent = request.META['HTTP_USER_AGENT'] data.info = json.loads(request.POST.get('data', '{}')) screen = data.info.get('screen', {}) if screen and 'height' in screen and 'width' in screen: data.screensize = '%sx%s' % (screen['width'], screen['height']) window = data.info.get('window', {}) if window and 'outerHeight' in window and 'outerWidth' in window: data.windowsize = '%sx%s' % (window['outerWidth'], window['outerHeight']) if not data.timesseen: data.timesseen = 0 data.timesseen += 1 data.lastseen = datetime.now() data.save() tasks.parse_data.delay(data.session_key) return data def get_id(self): return self.user and ox.toAZ(self.user.id) or self.session_key def json(self, keys=None, user=None): ua = ox.parse_useragent(self.useragent or '') j = { 'browser': ua['browser']['string'], 'disabled': False, 'email': '', 'firstseen': self.firstseen, 'ip': self.ip, 'id': self.get_id(), 'lastseen': self.lastseen, 'level': 'robot' if ua['robot']['name'] else 'guest', 'location': self.location, 'newsletter': False, 'notes': '', 'numberoflists': 0, 'screensize': self.screensize, 'system': ua['system']['string'], 'timesseen': self.timesseen, 'username': self.username or '', 'useragent': self.useragent, 'windowsize': self.windowsize, } if self.user: p = self.user.get_profile() j['disabled'] = not self.user.is_active j['email'] = self.user.email j['groups'] = [g.name for g in self.user.groups.all()] j['level'] = p.get_level() j['newsletter'] = p.newsletter j['notes'] = p.notes j['numberoflists'] = self.numberoflists if keys: for key in j.keys(): if key not in keys: del j[key] return j class UserProfile(models.Model): reset_code = models.CharField(max_length=255, blank=True, null=True, unique=True) user = models.ForeignKey(User, unique=True, related_name='profile') level = models.IntegerField(default=1) files_updated = models.DateTimeField(default=datetime.now) newsletter = models.BooleanField(default=True) ui = DictField(default={}) preferences = DictField(default={}) notes = models.TextField(default='') def __unicode__(self): return self.user.username def get_ui(self): return get_ui(self.ui, self.user) def set_level(self, level): self.level = settings.CONFIG['userLevels'].index(level) if self.level == len(settings.CONFIG['userLevels']) - 1: if not self.user.is_superuser: self.user.is_superuser = True self.user.save() elif self.user.is_superuser: self.user.is_superuser = False self.user.save() def get_level(self): #django superuser should always be admin if self.user.is_superuser: if self.level != len(settings.CONFIG['userLevels']) - 1: self.level = len(settings.CONFIG['userLevels']) - 1 self.save() return settings.CONFIG['userLevels'][self.level] def capability(self, capability): return settings.CONFIG['capabilities'][capability].get(self.get_level()) == True def user_post_save(sender, instance, **kwargs): profile, new = UserProfile.objects.get_or_create(user=instance) if new and instance.is_superuser: profile.level = len(settings.CONFIG['userLevels']) - 1 profile.newsletter = True profile.save() SessionData.objects.filter(user=instance).update(level=profile.level, username=instance.username) models.signals.post_save.connect(user_post_save, sender=User) def profile_post_save(sender, instance, **kwargs): SessionData.objects.filter(user=instance.user).update(level=instance.level, username=instance.user.username) models.signals.post_save.connect(profile_post_save, sender=UserProfile) def get_ui(user_ui, user=None): ui = {} config = copy.deepcopy(settings.CONFIG) ui.update(config['user']['ui']) def update_ui(ui, new): ''' only update set keys in dicts ''' for key in new: if isinstance(new[key], dict) and key in ui: ui[key] = update_ui(ui[key], new[key]) elif isinstance(ui, dict): ui[key] = new[key] return ui ui = update_ui(ui, user_ui) if not 'lists' in ui: ui['lists'] = {} def add(lists, section): ids = [] for l in lists: qs = Position.objects.filter(section=section) if section == 'featured': try: pos = Position.objects.get(list=l, section=section) created = False except Position.DoesNotExist: pos = Position(list=l, section=section, user=l.user) pos.save() created = True else: pos, created = Position.objects.get_or_create(list=l, user=user, section=section) qs = qs.filter(user=user) if created: pos.position = qs.aggregate(Max('position'))['position__max'] + 1 pos.save() id = l.get_id() ''' if id not in ui['lists']: ui['lists'][id] = {} ui['lists'][id].update(ui['lists']['']) ''' ids.append(id) return ids def add_texts(texts, section): P = text.models.Position ids = [] for t in texts: qs = P.objects.filter(section=section) if section == 'featured': try: pos = P.objects.get(text=t, section=section) created = False except P.DoesNotExist: pos = P(text=t, section=section, user=t.user) pos.save() created = True else: pos, created = P.objects.get_or_create(text=t, user=user, section=section) qs = qs.filter(user=user) if created: pos.position = qs.aggregate(Max('position'))['position__max'] + 1 pos.save() ids.append(t.get_id()) return ids ids = [''] if user: ids += add(user.lists.exclude(status="featured"), 'personal') ids += add(user.subscribed_lists.filter(status='public'), 'public') ids += add(List.objects.filter(status='featured'), 'featured') for i in ui['lists'].keys(): if i not in ids: del ui['lists'][i] tids = [''] if user: tids += add_texts(user.texts.exclude(status="featured"), 'personal') tids += add_texts(user.subscribed_texts.filter(status='public'), 'public') tids += add_texts(text.models.Text.objects.filter(status='featured'), 'featured') return ui def init_user(user, request=None): if request: SessionData.get_or_create(request) if user.is_anonymous(): result = settings.CONFIG['user'].copy() result['ui'] = get_ui(json.loads(request.session.get('ui', '{}'))) else: profile = user.get_profile() result = {} for key in ('username', ): result[key] = getattr(user, key) result['level'] = profile.get_level() result['groups'] = [g.name for g in user.groups.all()] result['email'] = user.email result['newsletter'] = profile.newsletter result['ui'] = profile.get_ui() result['volumes'] = [v.json() for v in user.volumes.all()] return result def user_json(user, keys=None): p = user.get_profile() j = { 'disabled': not user.is_active, 'email': user.email, 'firstseen': user.date_joined, 'id': ox.toAZ(user.id), 'lastseen': user.last_login, 'level': p.get_level(), 'newsletter': p.newsletter, 'notes': p.notes, 'numberoflists': user.lists.count(), 'username': user.username, } if keys: for key in j.keys(): if key not in keys: del j[key] return j