diff --git a/chrono/agendas/migrations/0030_auto_20191107_1200.py b/chrono/agendas/migrations/0030_auto_20191107_1200.py new file mode 100644 index 00000000..8e551bdc --- /dev/null +++ b/chrono/agendas/migrations/0030_auto_20191107_1200.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations +from django.utils.text import slugify + + +def generate_slug(instance, **query_filters): + base_slug = slugify(instance.label) + slug = base_slug + i = 1 + while True: + queryset = instance._meta.model.objects.filter(slug=slug, **query_filters).exclude(pk=instance.pk) + if not queryset.exists(): + break + slug = '%s-%s' % (base_slug, i) + i += 1 + return slug + + +def set_slug_on_agendas(apps, schema_editor): + Agenda = apps.get_model('agendas', 'Agenda') + for agenda in Agenda.objects.all().order_by('-pk'): + if not Agenda.objects.filter(slug=agenda.slug).exclude(pk=agenda.pk).exists(): + continue + agenda.slug = generate_slug(agenda) + agenda.save(update_fields=['slug']) + + +def set_slug_on_desks(apps, schema_editor): + Desk = apps.get_model('agendas', 'Desk') + for desk in Desk.objects.all().order_by('-pk'): + if not Desk.objects.filter(slug=desk.slug, agenda=desk.agenda).exclude(pk=desk.pk).exists(): + continue + desk.slug = generate_slug(desk, agenda=desk.agenda) + desk.save(update_fields=['slug']) + + +def set_slug_on_meetingtypes(apps, schema_editor): + MeetingType = apps.get_model('agendas', 'MeetingType') + for meetingtype in MeetingType.objects.all().order_by('-pk'): + if not MeetingType.objects.filter(slug=meetingtype.slug, agenda=meetingtype.agenda).exclude(pk=meetingtype.pk).exists(): + continue + meetingtype.slug = generate_slug(meetingtype, agenda=meetingtype.agenda) + meetingtype.save(update_fields=['slug']) + + +class Migration(migrations.Migration): + + dependencies = [ + ('agendas', '0029_auto_20191106_1320'), + ] + + operations = [ + migrations.RunPython(set_slug_on_agendas, lambda x, y: None), + migrations.RunPython(set_slug_on_desks, lambda x, y: None), + migrations.RunPython(set_slug_on_meetingtypes, lambda x, y: None), + ] diff --git a/chrono/agendas/migrations/0031_auto_20191107_1225.py b/chrono/agendas/migrations/0031_auto_20191107_1225.py new file mode 100644 index 00000000..e0c900c1 --- /dev/null +++ b/chrono/agendas/migrations/0031_auto_20191107_1225.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.18 on 2019-11-07 11:25 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('agendas', '0030_auto_20191107_1200'), + ] + + operations = [ + migrations.AlterField( + model_name='agenda', + name='slug', + field=models.SlugField(max_length=160, unique=True, verbose_name='Identifier'), + ), + migrations.AlterUniqueTogether( + name='desk', + unique_together=set([('agenda', 'slug')]), + ), + migrations.AlterUniqueTogether( + name='meetingtype', + unique_together=set([('agenda', 'slug')]), + ), + ] diff --git a/chrono/agendas/models.py b/chrono/agendas/models.py index 5e54e45c..5c347f7e 100644 --- a/chrono/agendas/models.py +++ b/chrono/agendas/models.py @@ -49,6 +49,16 @@ def is_midnight(dtime): return dtime.hour == 0 and dtime.minute == 0 +def generate_slug(instance, **query_filters): + base_slug = slugify(instance.label) + slug = base_slug + i = 1 + while instance._meta.model.objects.filter(slug=slug, **query_filters).exists(): + slug = '%s-%s' % (base_slug, i) + i += 1 + return slug + + class ICSError(Exception): pass @@ -59,7 +69,7 @@ class AgendaImportError(Exception): class Agenda(models.Model): label = models.CharField(_('Label'), max_length=150) - slug = models.SlugField(_('Identifier'), max_length=160) + slug = models.SlugField(_('Identifier'), max_length=160, unique=True) kind = models.CharField(_('Kind'), max_length=20, choices=AGENDA_KINDS, default='events') minimal_booking_delay = models.PositiveIntegerField( _('Minimal booking delay (in days)'), default=1) @@ -77,17 +87,7 @@ class Agenda(models.Model): def save(self, *args, **kwargs): if not self.slug: - base_slug = slugify(self.label) - slug = base_slug - i = 1 - while True: - try: - Agenda.objects.get(slug=slug) - except self.DoesNotExist: - break - slug = '%s-%s' % (base_slug, i) - i += 1 - self.slug = slug + self.slug = generate_slug(self) super(Agenda, self).save(*args, **kwargs) def get_absolute_url(self): @@ -149,6 +149,9 @@ class Agenda(models.Model): except Group.DoesNotExist: raise AgendaImportError(_('Missing "%s" role') % permissions[permission]) agenda, created = cls.objects.get_or_create(slug=data['slug'], defaults=data) + if not created: + for k, v in data.items(): + setattr(agenda, k, v) if data['kind'] == 'events': if overwrite: Event.objects.filter(agenda=agenda).delete() @@ -252,25 +255,21 @@ class MeetingType(models.Model): class Meta: ordering = ['duration', 'label'] + unique_together = ['agenda', 'slug'] def save(self, *args, **kwargs): if not self.slug: - base_slug = slugify(self.label) - slug = base_slug - i = 1 - while True: - try: - MeetingType.objects.get(slug=slug, agenda=self.agenda) - except self.DoesNotExist: - break - slug = '%s-%s' % (base_slug, i) - i += 1 - self.slug = slug + self.slug = generate_slug(self, agenda=self.agenda) super(MeetingType, self).save(*args, **kwargs) @classmethod def import_json(cls, data): - return cls(**data) + meeting_type, created = cls.objects.get_or_create( + slug=data['slug'], agenda=data['agenda'], defaults=data) + if not created: + for k, v in data.items(): + setattr(meeting_type, k, v) + return meeting_type def export_json(self): return { @@ -307,15 +306,7 @@ class Event(models.Model): def save(self, *args, **kwargs): self.check_full() if not self.slug: - base_slug = slugify(self.label) - slug = base_slug - i = 1 - while True: - if not Event.objects.filter(slug=slug).exists(): - break - slug = '%s-%s' % (base_slug, i) - i += 1 - self.slug = slug + self.slug = generate_slug(self) return super(Event, self).save(*args, **kwargs) def check_full(self): @@ -447,27 +438,22 @@ class Desk(models.Model): class Meta: ordering = ['label'] + unique_together = ['agenda', 'slug'] def save(self, *args, **kwargs): if not self.slug: - base_slug = slugify(self.label) - slug = base_slug - i = 1 - while True: - try: - Desk.objects.get(slug=slug, agenda=self.agenda) - except self.DoesNotExist: - break - slug = '%s-%s' % (base_slug, i) - i += 1 - self.slug = slug + self.slug = generate_slug(self, agenda=self.agenda) super(Desk, self).save(*args, **kwargs) @classmethod def import_json(cls, data): timeperiods = data.pop('timeperiods') exceptions = data.pop('exceptions') - instance, created = cls.objects.get_or_create(**data) + instance, created = cls.objects.get_or_create( + slug=data['slug'], agenda=data['agenda'], defaults=data) + if not created: + for k, v in data.items(): + setattr(instance, k, v) for timeperiod in timeperiods: timeperiod['desk'] = instance TimePeriod.import_json(timeperiod).save()