pandora/pandora/annotation/models.py

251 lines
9 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division, with_statement
2012-01-17 08:58:33 +00:00
import re
import unicodedata
from django.db import models
2012-01-17 08:58:33 +00:00
from django.db.models import Q
from django.contrib.auth.models import User
2011-11-02 14:42:07 +00:00
from django.conf import settings
2012-02-01 15:25:18 +00:00
from django.db.models.signals import pre_delete
2011-01-28 08:43:46 +00:00
import ox
2011-10-02 18:16:28 +00:00
from archive import extract
from clip.models import Clip
2012-01-31 17:06:10 +00:00
from changelog.models import Changelog
2011-10-02 18:16:28 +00:00
from item.utils import sort_string
2011-06-17 07:44:45 +00:00
import managers
import utils
2012-05-27 14:21:08 +00:00
from tasks import update_matches, update_matches, update_item
2010-12-28 14:04:28 +00:00
2012-05-27 14:21:08 +00:00
def get_super_matches(obj, model):
2012-01-17 08:58:33 +00:00
super_matches = []
q = Q(name_find__contains=" " + obj.name)|Q(name_find__contains="|%s"%obj.name)
for name in obj.alternativeNames:
q = q|Q(name_find__contains=" " + name)|Q(name_find__contains="|%s"%name)
for p in model.objects.filter(q).exclude(id=obj.id):
for othername in [p.name] + list(p.alternativeNames):
for name in [obj.name] + list(obj.alternativeNames):
if name in othername:
super_matches.append(othername)
2012-05-27 14:21:08 +00:00
return super_matches
2012-01-17 08:58:33 +00:00
2012-05-27 14:21:08 +00:00
def get_matches(obj, model, layer_type, qs=None):
super_matches = obj.get_super_matches()
2012-01-17 08:58:33 +00:00
exact = [l['id'] for l in filter(lambda l: l['type'] == layer_type, settings.CONFIG['layers'])]
if exact:
q = Q(value__iexact=obj.name)
for name in obj.alternativeNames:
q = q|Q(value__iexact=name)
f = q&Q(layer__in=exact)
else:
f = None
has_type = 'has%ss' % layer_type.capitalize()
contains = [l['id'] for l in filter(lambda l: l.get(has_type), settings.CONFIG['layers'])]
if contains:
2012-05-27 11:52:12 +00:00
name = ox.decode_html(obj.name)
2012-03-09 22:37:54 +00:00
q = Q(findvalue__icontains=" " + name)|Q(findvalue__istartswith=name)
2012-01-17 08:58:33 +00:00
for name in obj.alternativeNames:
2012-05-27 11:52:12 +00:00
name = ox.decode_html(name)
q = q|Q(findvalue__icontains=" " + name)|Q(findvalue__istartswith=name)
2012-01-17 08:58:33 +00:00
contains_matches = q&Q(layer__in=contains)
if f:
f = contains_matches | f
else:
f = contains_matches
matches = []
2012-05-27 14:21:08 +00:00
if not qs:
qs = Annotation.objects.all()
for a in qs.filter(f):
2012-03-09 22:37:54 +00:00
value = a.findvalue.lower()
2012-01-17 08:58:33 +00:00
for name in super_matches:
2012-05-27 11:52:12 +00:00
name = ox.decode_html(name)
2012-01-17 08:58:33 +00:00
value = value.replace(name.lower(), '')
for name in [obj.name] + list(obj.alternativeNames):
name = name.lower()
2012-05-27 11:52:12 +00:00
name = ox.decode_html(name)
if name in value and (exact or re.compile('((^|\s)%s([\.,;:!?\-\/\s]|$))'%re.escape(name)).findall(value)):
2012-01-17 08:58:33 +00:00
matches.append(a.id)
break
if not matches:
matches = [-1]
return Annotation.objects.filter(id__in=matches)
2011-02-11 10:21:25 +00:00
2010-11-28 16:03:23 +00:00
class Annotation(models.Model):
2011-06-17 07:44:45 +00:00
objects = managers.AnnotationManager()
2011-01-01 11:44:42 +00:00
#FIXME: here having a item,start index would be good
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User)
2011-01-06 03:11:00 +00:00
item = models.ForeignKey('item.Item', related_name='annotations')
2011-10-02 18:16:28 +00:00
clip = models.ForeignKey('clip.Clip', null=True, related_name='annotations')
public_id = models.CharField(max_length=128, unique=True, null=True)
#seconds
2011-08-23 10:47:59 +00:00
start = models.FloatField(default=-1, db_index=True)
end = models.FloatField(default=-1, db_index=True)
2011-11-02 14:06:34 +00:00
layer = models.CharField(max_length=255, db_index=True)
value = models.TextField()
findvalue = models.TextField(null=True)
sortvalue = models.CharField(max_length=1000, null=True, blank=True, db_index=True)
def editable(self, user):
if user.is_authenticated():
2012-01-02 15:08:38 +00:00
if user.get_profile().capability('canEditAnnotations') or \
2011-01-21 09:31:49 +00:00
self.user == user or \
2012-02-08 10:45:33 +00:00
user.groups.filter(id__in=self.item.groups.all()).count() > 0:
return True
return False
2011-09-30 22:28:35 +00:00
def set_public_id(self):
2011-10-29 14:12:28 +00:00
if self.id:
2011-12-18 09:35:49 +00:00
public_id = Annotation.objects.filter(item=self.item, id__lt=self.id).count() + 1
2012-01-03 09:16:45 +00:00
if public_id > 1:
previous = Annotation.objects.filter(item=self.item,
id__lt=self.id).order_by('-id')[0]
if not previous.public_id:
previous.set_public_id()
public_id = ox.fromAZ(previous.public_id.split('/')[-1]) + 1
2011-12-18 09:35:49 +00:00
self.public_id = "%s/%s" % (self.item.itemId, ox.toAZ(public_id))
2011-10-29 14:12:28 +00:00
Annotation.objects.filter(id=self.id).update(public_id=self.public_id)
2011-09-30 22:28:35 +00:00
2012-01-10 16:00:41 +00:00
@classmethod
def public_layers(self):
layers = []
for layer in settings.CONFIG['layers']:
if not layer.get('private', False):
layers.append(layer['id'])
return layers
2011-12-26 14:30:30 +00:00
def get_layer(self):
for layer in settings.CONFIG['layers']:
if layer['id'] == self.layer:
return layer
return {}
2011-08-23 10:47:59 +00:00
def save(self, *args, **kwargs):
2011-10-29 14:12:28 +00:00
set_public_id = not self.id or not self.public_id
2011-12-26 14:30:30 +00:00
layer = self.get_layer()
2011-11-03 11:44:53 +00:00
if self.value:
2011-12-26 14:43:04 +00:00
self.value = utils.cleanup_value(self.value, layer['type'])
self.findvalue = ox.decode_html(ox.strip_tags(re.sub('<br */?>\n?', ' ', self.value))).replace('\n', ' ')
self.findvalue = unicodedata.normalize('NFKD', self.findvalue).lower()
2011-12-26 14:43:04 +00:00
sortvalue = sort_string(self.findvalue)
2011-11-03 11:44:53 +00:00
if sortvalue:
self.sortvalue = sortvalue[:900]
2011-11-03 11:44:53 +00:00
else:
self.sortvalue = None
else:
self.findvalue = None
2011-11-03 11:44:53 +00:00
self.sortvalue = None
2011-10-04 09:39:00 +00:00
#no clip or update clip
2012-04-02 15:33:09 +00:00
if self.layer in settings.CONFIG.get('clipLayers', []):
if not self.clip or self.start != self.clip.start or self.end != self.clip.end:
self.clip, created = Clip.get_or_create(self.item, self.start, self.end)
elif self.clip:
self.clip = None
2011-10-04 09:39:00 +00:00
2011-08-23 10:47:59 +00:00
super(Annotation, self).save(*args, **kwargs)
if set_public_id:
self.set_public_id()
2011-11-02 13:26:38 +00:00
2011-12-18 09:47:12 +00:00
if self.clip:
Clip.objects.filter(**{
'id': self.clip.id,
self.layer: False
}).update(**{self.layer: True})
#update clip.findvalue
self.clip.save()
2011-11-02 13:26:38 +00:00
2012-02-01 15:25:18 +00:00
#editAnnotations needs to be in snyc
2012-03-09 22:57:17 +00:00
if layer.get('type') == 'place' or layer.get('hasPlaces'):
2012-05-27 14:21:08 +00:00
update_matches(self.id, 'place')
2012-02-01 15:25:18 +00:00
if layer.get('type') == 'event' or layer.get('hasEvents'):
2012-05-27 14:21:08 +00:00
update_matches(self.id, 'event')
2011-01-18 09:54:14 +00:00
2012-02-28 20:02:50 +00:00
def delete(self, *args, **kwargs):
super(Annotation, self).delete(*args, **kwargs)
if self.clip and self.clip.annotations.count() == 0:
2012-02-28 20:02:50 +00:00
self.clip.delete()
self.item.update_find()
self.item.update_sort()
self.item.update_facets()
2012-02-01 15:25:18 +00:00
def cleanup_undefined_relations(self):
layer = self.get_layer()
if layer.get('type') == 'place':
for p in self.places.filter(defined=False):
if p.annotations.exclude(id=self.id).count() == 0:
p.delete()
elif layer.get('type') == 'event':
for e in self.events.filter(defined=False):
if e.annotations.exclude(id=self.id).count() == 0:
e.delete()
2012-01-12 19:32:54 +00:00
def json(self, layer=False, keys=None, user=None):
2011-06-01 11:03:07 +00:00
j = {
2010-12-28 14:04:28 +00:00
'user': self.user.username,
}
2012-01-12 19:32:54 +00:00
for key in ('id', 'in', 'out', 'value', 'created', 'modified'):
j[key] = getattr(self, {
2011-10-04 09:39:00 +00:00
'hue': 'clip__hue',
'id': 'public_id',
'in': 'start',
2011-10-04 09:39:00 +00:00
'lightness': 'clip__lightness',
'out': 'end',
2011-10-04 09:39:00 +00:00
'saturation': 'clip__saturation',
'volume': 'clip__volume',
2012-01-12 19:32:54 +00:00
}.get(key, key))
j['duration'] = abs(j['out'] - j['in'])
2012-02-08 11:00:11 +00:00
if user:
j['editable'] = self.editable(user)
2012-01-12 19:32:54 +00:00
l = self.get_layer()
if l['type'] == 'place':
2012-02-01 16:35:57 +00:00
qs = self.places.all()
2012-01-12 19:32:54 +00:00
if qs.count() > 0:
j['place'] = qs[0].json(user=user)
else:
j['place'] = {}
2012-01-12 19:32:54 +00:00
elif l['type'] == 'event':
2012-02-01 16:35:57 +00:00
qs = self.events.all()
2012-01-12 19:32:54 +00:00
if qs.count() > 0:
j['event'] = qs[0].json(user=user)
else:
j['event'] = {}
2012-01-12 19:32:54 +00:00
2011-10-19 15:55:29 +00:00
if layer or (keys and 'layer' in keys):
2011-11-02 14:42:07 +00:00
j['layer'] = self.layer
2011-06-16 20:00:10 +00:00
if keys:
_j = {}
for key in keys:
if key in j:
_j[key] = j[key]
j = _j
2011-08-19 14:43:05 +00:00
if 'videoRatio' in keys:
streams = self.item.streams()
if streams:
j['videoRatio'] = streams[0].aspect_ratio
2011-06-01 11:03:07 +00:00
return j
2010-12-28 14:04:28 +00:00
2012-01-31 17:06:10 +00:00
def log(self):
c = Changelog(type='annotation')
c.value = self.json()
c.save()
2010-11-28 16:31:53 +00:00
def __unicode__(self):
return u"%s %s-%s" %(self.public_id, self.start, self.end)
2011-06-04 16:19:06 +00:00
2012-02-01 15:25:18 +00:00
def cleanup_related(sender, **kwargs):
kwargs['instance'].cleanup_undefined_relations()
pre_delete.connect(cleanup_related, sender=Annotation)