diff --git a/pandora/annotation/models.py b/pandora/annotation/models.py index a4220f8b1..c42d0ecc5 100644 --- a/pandora/annotation/models.py +++ b/pandora/annotation/models.py @@ -7,6 +7,8 @@ from django.db import models from django.db.models import Q from django.contrib.auth.models import User from django.conf import settings +from django.db.models.signals import pre_delete + import ox from archive import extract @@ -152,17 +154,23 @@ class Annotation(models.Model): #update clip.findvalue self.clip.save() - if filter(lambda l: l['type'] == 'place' or l.get('hasPlaces'), - settings.CONFIG['layers']): - #update_matching_places.delay(self.id) - #editAnnotations needs to be in snyc + #editAnnotations needs to be in snyc + if layer.get('type') == 'place' or layer.get('hasPlace'): update_matching_places(self.id) - if filter(lambda l: l['type'] == 'event' or l.get('hasEvents'), - settings.CONFIG['layers']): - #update_matching_events.delay(self.id) - #editAnnotations needs to be in snyc + if layer.get('type') == 'event' or layer.get('hasEvents'): update_matching_events(self.id) + 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() + def json(self, layer=False, keys=None, user=None): j = { 'user': self.user.username, @@ -181,11 +189,11 @@ class Annotation(models.Model): l = self.get_layer() if l['type'] == 'place': - qs = self.places.all() + qs = self.places.filter(defined=True) if qs.count() > 0: j['place'] = qs[0].json(user=user) elif l['type'] == 'event': - qs = self.events.all() + qs = self.events.filter(defined=True) if qs.count() > 0: j['event'] = qs[0].json(user=user) @@ -211,3 +219,6 @@ class Annotation(models.Model): def __unicode__(self): return u"%s %s-%s" %(self.public_id, self.start, self.end) +def cleanup_related(sender, **kwargs): + kwargs['instance'].cleanup_undefined_relations() +pre_delete.connect(cleanup_related, sender=Annotation) diff --git a/pandora/annotation/tasks.py b/pandora/annotation/tasks.py index 891ee44f4..712027248 100644 --- a/pandora/annotation/tasks.py +++ b/pandora/annotation/tasks.py @@ -9,6 +9,12 @@ import models def update_matching_events(id): from event.models import Event annotation = models.Annotation.objects.get(pk=id) + for e in annotation.events.filter(defined=False): + if e.annotations.exclude(id=id).count() == 0: + e.delete() + if annotation.get_layer().get('type') == 'event' \ + and annotation.events.count() == 0: + annotations.events.add(Event.get_or_create(annotation.value)) for e in annotation.events.all(): e.update_matches() ids = [e['id'] for e in Event.objects.all().values('id')] @@ -23,6 +29,12 @@ def update_matching_events(id): def update_matching_places(id): from place.models import Place annotation = models.Annotation.objects.get(pk=id) + for p in annotation.places.filter(defined=False): + if p.annotations.exclude(id=id).count() == 0: + p.delete() + if annotation.get_layer().get('type') == 'place' \ + and annotation.places.count() == 0: + annotation.places.add(Place.get_or_create(annotation.value)) for p in annotation.places.all(): p.update_matches() ids = [e['id'] for e in Place.objects.all().values('id')] diff --git a/pandora/event/models.py b/pandora/event/models.py index bf6f77c19..34a1f9968 100644 --- a/pandora/event/models.py +++ b/pandora/event/models.py @@ -32,6 +32,7 @@ class Event(models.Model): created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) + defined = models.BooleanField(default=False) user = models.ForeignKey(User, null=True, related_name='events') @@ -46,14 +47,14 @@ class Event(models.Model): #start yyyy-mm-dd|mm-dd|dow 00:00|00:00 start = models.CharField(default='', max_length=255) - startTime = models.BigIntegerField(default=0) + startTime = models.BigIntegerField(default=None, null=True) #end yyyy-mm-dd|mm-dd|dow 00:00|00:01 end = models.CharField(default='', max_length=255) - endTime = models.BigIntegerField(default=0) + endTime = models.BigIntegerField(default=None, null=True) duration = models.CharField(default='', max_length=255) - durationTime = models.BigIntegerField(default=0) + durationTime = models.BigIntegerField(default=None, null=True) type = models.CharField(default='', max_length=255) @@ -64,9 +65,21 @@ class Event(models.Model): def __unicode__(self): return self.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 editable(self, user): if user and not user.is_anonymous() \ - and (self.user == user or user.get_profile().capability('canEditEvents')): + and (not self.user or \ + self.user == user or \ + user.get_profile().capability('canEditEvents')): return True return False @@ -109,9 +122,19 @@ class Event(models.Model): if not self.name_sort: self.set_name_sort() self.name_find = '||' + self.name + '||'.join(self.alternativeNames) + '||' - self.durationTime = self.endTime - self.startTime + self.defined = len(filter(None, [getattr(self, key) + for key in ('start', 'end', 'startTime', 'endTime')])) > 0 + if self.defined: + self.durationTime = self.endTime - self.startTime + super(Event, self).save(*args, **kwargs) + def make_undefined(self): + self.defined = False + self.start = '' + self.end = '' + self.durationTime = self.endTime = self.startTime = None + def get_id(self): return ox.toAZ(self.id) diff --git a/pandora/event/views.py b/pandora/event/views.py index fd2964d98..f25ca0eb1 100644 --- a/pandora/event/views.py +++ b/pandora/event/views.py @@ -30,11 +30,14 @@ def addEvent(request): data = json.loads(request.POST['data']) existing_names = [] exists = False - for name in [data['name']] + data.get('alternativeNames', []): - if models.Event.objects.filter(name_find__icontains=u'|%s|'%name).count() != 0: + names = [data['name']] + data.get('alternativeNames', []) + for name in names: + if models.Event.objects.filter(defined=True, + name_find__icontains=u'|%s|'%name).count() != 0: exists = True existing_names.append(name) if not exists: + models.Event.objects.filter(defined=False, name__in=names).delete() event = models.Event(name = data['name']) for key in ('start', 'startTime', 'end', 'endTime', 'duration', 'durationTime', 'type', 'alternativeNames'): @@ -74,10 +77,12 @@ def editEvent(request): conflict_names = [] names = [data.get('name', event.name)] + data.get('alternativeNames', []) for name in names: - if models.Event.objects.filter(name_find__icontains=u'|%s|'%name).exclude(id=event.id).count() != 0: + if models.Event.objects.filter(defined=True, + name_find__icontains=u'|%s|'%name).exclude(id=event.id).count() != 0: conflict = True conflict_names.append(name) if not conflict: + models.Event.objects.filter(defined=False, name__in=names).delete() if 'name' in data: event.set_name_sort(data['name']) for key in ('name', 'start', 'startTime', 'end', 'endTime', 'duration', 'durationTime', diff --git a/pandora/place/models.py b/pandora/place/models.py index 6dba18bd8..bb9da4232 100644 --- a/pandora/place/models.py +++ b/pandora/place/models.py @@ -23,6 +23,8 @@ class Place(models.Model): ''' created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) + defined = models.BooleanField(default=True) + user = models.ForeignKey(User, null=True, related_name='places') name = models.CharField(max_length=1024) @@ -30,20 +32,20 @@ class Place(models.Model): name_sort = models.CharField(max_length=200) name_find = models.TextField(default='', editable=False) - geoname = models.CharField(max_length=1024, unique=True) - geoname_sort = models.CharField(max_length=1024, unique=True) + geoname = models.CharField(max_length=1024, unique=True, null=True) + geoname_sort = models.CharField(max_length=1024, unique=True, null=True) countryCode = models.CharField(max_length=16, default='') wikipediaId = models.CharField(max_length=1000, blank=True) type = models.CharField(max_length=1000, default='') - south = models.FloatField(default=0) - west = models.FloatField(default=0) - north = models.FloatField(default=0) - east = models.FloatField(default=0) - lat = models.FloatField(default=0) - lng = models.FloatField(default=0) - area = models.FloatField(default=0) + south = models.FloatField(default=None, null=True) + west = models.FloatField(default=None, null=True) + north = models.FloatField(default=None, null=True) + east = models.FloatField(default=None, null=True) + lat = models.FloatField(default=None, null=True) + lng = models.FloatField(default=None, null=True) + area = models.FloatField(default=None, null=True) matches = models.IntegerField(default=0) items = models.ManyToManyField(Item, blank=True, related_name='places') @@ -57,9 +59,21 @@ class Place(models.Model): def __unicode__(self): return self.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 editable(self, user): if user and not user.is_anonymous() \ - and (self.user == user or user.get_profile().capability('canEditPlaces')): + and (not self.user or \ + self.user == user or \ + user.get_profile().capability('canEditPlaces')): return True return False @@ -69,9 +83,10 @@ class Place(models.Model): def json(self, keys=None, user=None): j = { 'id': self.get_id(), - 'user': self.user.username, 'editable': self.editable(user) } + if self.user: + j['user'] = self.user.username for key in ('created', 'modified', 'name', 'alternativeNames', 'geoname', 'countryCode', 'south', 'west', 'north', 'east', @@ -106,18 +121,25 @@ class Place(models.Model): self.matches = numberofmatches self.save() + def make_undefined(self): + self.defined = False + self.south = None + self.west = None + self.north = None + self.east = None + self.lat = None + self.lng = None + self.area = None + def save(self, *args, **kwargs): if not self.name_sort: self.name_sort = self.name #', '.join(self.name) - self.geoname_sort = ', '.join(reversed(self.geoname.split(', '))) + if self.geoname: + self.geoname_sort = ', '.join(reversed(self.geoname.split(', '))) self.name_find = '|%s|'%'|'.join([self.name]+list(self.alternativeNames)) - #update center - #self.lat = ox.location.center(self.south, self.north) - #self.lng = ox.location.center(self.east, self.west) - - #update area - #self.area= ox.location.area(self.south, self.west, self.north, self.east) + self.defined = len(filter(None, [getattr(self, key) + for key in ('south', 'west', 'north', 'east')])) > 0 super(Place, self).save(*args, **kwargs) diff --git a/pandora/place/views.py b/pandora/place/views.py index e32366617..77942a640 100644 --- a/pandora/place/views.py +++ b/pandora/place/views.py @@ -19,7 +19,6 @@ import tasks @login_required_json def addPlace(request): - #FIXME: require admin ''' param data { name: "", @@ -36,20 +35,24 @@ def addPlace(request): type: "" } ''' + #FIXME: check permissions data = json.loads(request.POST['data']) exists = False existing_names = [] existing_geoname = '' names = data.pop('name') for name in [names] + data.get('alternativeNames', []): - if models.Place.objects.filter(name_find__icontains=u'|%s|'%name).count() != 0: + if models.Place.objects.filter(defined=True, + name_find__icontains=u'|%s|'%name).count() != 0: exists = True existing_names.append(name) if 'geoname' in data: - if models.Place.objects.filter(geoname=data['geoname']).count() > 0: + if models.Place.objects.filter(defined=True, + geoname=data['geoname']).count() > 0: exists = True existing_geoname = data['geoname'] if not exists: + models.Place.objects.filter(defined=False, name__in=names).delete() place = models.Place() place.user = request.user place.name = names @@ -96,14 +99,17 @@ def editPlace(request): alternative_names = filter(lambda n: n.strip(), alternative_names) data['alternativeNames'] = alternative_names for name in names + alternative_names: - if models.Place.objects.filter(name_find__icontains=u'|%s|'%name).exclude(id=place.id).count() != 0: + if models.Place.objects.filter(defined=True, + name_find__icontains=u'|%s|'%name).exclude(id=place.id).count() != 0: conflict = True conflict_names.append(name) if 'geoname' in data: - if models.Place.objects.filter(geoname=data['geoname']).exclude(id=place.id).count() != 0: + if models.Place.objects.filter(defined=True, + geoname=data['geoname']).exclude(id=place.id).count() != 0: conflict = True conflict_geoname = data['geoname'] if not conflict: + models.Place.objects.filter(defined=False, name__in=names+alternative_names).delete() for key in data: if key != 'id': value = data[key] diff --git a/static/js/pandora/URL.js b/static/js/pandora/URL.js index e0dbd65c2..6d5a79389 100644 --- a/static/js/pandora/URL.js +++ b/static/js/pandora/URL.js @@ -121,8 +121,6 @@ pandora.URL = (function() { if (state.find) { if (!state.item) { set.find = state.find; - } else if (pandora.isItemFind(state.find)) { - set.itemFind = state.find; } }