pandora/pandora/entity/models.py
2015-02-03 18:44:05 +01:00

165 lines
5.5 KiB
Python

# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division, with_statement
import os
import re
from glob import glob
from urllib import quote, unquote
from django.db import models
from django.db.models import Max
from django.contrib.auth.models import User
from django.db.models.signals import pre_delete
from django.conf import settings
import ox
from ox.django import fields
from person.models import get_name_sort
from item.utils import get_by_id
import managers
class Entity(models.Model):
class Meta:
unique_together = ("type", "name")
user = models.ForeignKey(User, related_name='entities', null=True, default=None)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
type = models.CharField(max_length=255)
name = models.CharField(max_length=255)
alternativeNames = fields.TupleField(default=[])
data = fields.DictField(default={}, editable=False)
matches = models.IntegerField(default=0)
objects = managers.EntityManager()
name_sort = models.CharField(max_length=255, null=True)
name_find = models.TextField(default='', editable=True)
def save(self, *args, **kwargs):
entity = get_by_id(settings.CONFIG['entities'], self.type)
if entity.get('sortType') == 'person' and self.name:
if isinstance(self.name, str):
self.name = self.name.decode('utf-8')
self.name_sort = get_name_sort(self.name)[:255].lower()
else:
self.name_sort = ox.sort_string(self.name or u'')[:255].lower() or None
self.name_find = '||' + self.name + '||'.join(self.alternativeNames) + '||'
super(Entity, self).save(*args, **kwargs)
self.update_matches()
def __unicode__(self):
return self.get_id()
@classmethod
def get(cls, id):
return cls.objects.get(pk=ox.fromAZ(id))
@classmethod
def get_by_name(cls, name):
return cls.objects.get(name_find__icontains=u'|%s|'%name)
@classmethod
def get_or_create(model, name):
qs = model.objects.filter(name_find__icontains=u'|%s|'%name)
if qs.count() == 0:
instance = model(name=name)
instance.save()
else:
instance = qs[0]
return instance
def get_absolute_url(self):
return ('/entities/%s' % quote(self.get_id())).replace('%3A', ':')
def get_id(self):
return ox.toAZ(self.id)
def editable(self, user, item=None):
if not user or user.is_anonymous():
return False
if user.is_staff or \
user.get_profile().capability('canEditEntities') == True or \
(item and item.editable(user)):
return True
return False
def edit(self, data):
for key in data:
if key == 'name':
data['name'] = re.sub(' \[\d+\]$', '', data['name']).strip()
if not data['name']:
data['name'] = "Unnamed"
name = data['name']
num = 1
while Entity.objects.filter(name=name, type=self.type).exclude(id=self.id).count()>0:
num += 1
name = data['name'] + ' [%d]' % num
self.name = name
elif key == 'type':
self.type = data[key]
elif key == 'alternativeNames':
self.alternativeNames = tuple([ox.escape_html(v) for v in data[key]])
else:
#FIXME: more data validation
if isinstance(data[key], basestring):
self.data[key] = ox.sanitize_html(data[key])
else:
self.data[key] = data[key]
def json(self, keys=None, user=None):
if not keys:
keys=[
'alternativeNames',
'editable',
'id',
'name',
'sortName',
'type',
'user',
] + self.data.keys()
response = {}
for key in keys:
if key == 'id':
response[key] = self.get_id()
elif key == 'editable':
response[key] = self.editable(user)
elif key == 'user':
response[key] = self.user and self.user.username
elif key in ('name', 'alternativeNames', 'type'):
response[key] = getattr(self, key)
elif key == 'sortName':
response[key] = self.name_sort
elif key in self.data:
response[key] = self.data[key]
return response
def update_matches(self):
import annotation.models
import item.models
import text.models
urls = [self.get_absolute_url()]
url = unquote(urls[0])
if url != urls[0]:
urls.append(url)
entity_layers = [l['id'] for l in settings.CONFIG['layers'] if l['type'] == 'entity']
if entity_layers:
matches = annotation.models.Annotation.objects.filter(layer__in=entity_layers, value=self.get_id()).count()
else:
matches = 0
for url in urls:
matches += annotation.models.Annotation.objects.filter(value__contains=url).count()
matches += item.models.Item.objects.filter(data__contains=url).count()
matches += text.models.Text.objects.filter(text__contains=url).count()
if matches != self.matches:
Entity.objects.filter(id=self.id).update(matches=matches)
self.matches = matches