api: add a field 'slug' to Event (#15726)

This commit is contained in:
Lauréline Guérin 2019-11-06 15:20:07 +01:00
parent befaa3b365
commit 0f4040f9a5
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
9 changed files with 129 additions and 7 deletions

View File

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
from django.utils.text import slugify
def set_slug_on_events(apps, schema_editor):
Event = apps.get_model('agendas', 'Event')
for event in Event.objects.filter(slug=''):
base_slug = slugify(event.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
event.slug = slug
event.save(update_fields=['slug'])
class Migration(migrations.Migration):
dependencies = [
('agendas', '0027_event_description'),
]
operations = [
migrations.AddField(
model_name='event',
name='slug',
field=models.SlugField(default='', max_length=160, verbose_name='Identifier'),
preserve_default=False,
),
migrations.RunPython(set_slug_on_events, lambda x, y: None),
]

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.18 on 2019-11-06 12:20
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('agendas', '0028_event_slug'),
]
operations = [
migrations.AlterField(
model_name='event',
name='slug',
field=models.SlugField(max_length=160, unique=True, verbose_name='Identifier'),
),
]

View File

@ -289,6 +289,7 @@ class Event(models.Model):
_('Places in waiting list'), default=0)
label = models.CharField(_('Label'), max_length=150, null=True, blank=True,
help_text=_('Optional label to identify this date.'))
slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
description = models.TextField(_('Description'), null=True, blank=True,
help_text=_('Optional event description.'))
full = models.BooleanField(default=False)
@ -305,6 +306,16 @@ 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
return super(Event, self).save(*args, **kwargs)
def check_full(self):
@ -345,6 +356,12 @@ class Event(models.Model):
def import_json(cls, data):
data['start_datetime'] = make_aware(datetime.datetime.strptime(
data['start_datetime'], '%Y-%m-%d %H:%M:%S'))
if 'slug' in data:
event, created = cls.objects.get_or_create(slug=data['slug'], defaults=data)
if not created:
for k, v in data.items():
setattr(event, k, v)
return event
return cls(**data)
def export_json(self):
@ -353,6 +370,7 @@ class Event(models.Model):
'places': self.places,
'waiting_list_places': self.waiting_list_places,
'label': self.label,
'slug': self.slug,
'description': self.description,
}

View File

@ -63,6 +63,16 @@ class AgendaEditForm(AgendaAddForm):
fields = ['label', 'slug', 'edit_role', 'view_role', 'minimal_booking_delay', 'maximal_booking_delay']
class NewEventForm(forms.ModelForm):
class Meta:
model = Event
widgets = {
'agenda': forms.HiddenInput(),
'start_datetime': DateTimeWidget(),
}
exclude = ['full', 'meeting_type', 'desk', 'slug']
class EventForm(forms.ModelForm):
class Meta:
model = Event
@ -220,9 +230,14 @@ class ImportEventsForm(forms.Form):
except ValueError:
raise ValidationError(_('Invalid file format. (number of places in waiting list, line %d)') % (i+1))
if len(csvline) >= 5:
event.label = ' '.join([force_text(x) for x in csvline[4:]])
event.label = force_text(csvline[4])
exclude = ['agenda', 'desk', 'meeting_type']
if len(csvline) >= 6:
event.slug = ' '.join([force_text(x) for x in csvline[5:]])
else:
exclude += ['slug']
try:
event.full_clean(exclude=['agenda', 'desk', 'meeting_type'])
event.full_clean(exclude=exclude)
except ValidationError as e:
errors = [
_('Invalid file format. (%(label)s: %(errors)s, line %(line)d)') % {

View File

@ -46,7 +46,7 @@
data-total="{{event.waiting_list_places}}" data-booked="{{event.waiting_list}}"
{% endif %}
><a rel="popup" href="{% if user_can_manage %}{% url 'chrono-manager-event-edit' pk=event.id %}{% else %}#{% endif %}">
{% if event.label %}{{event.label}} / {% endif %}
{% if event.label %}{{event.label}} {% endif %}[{% trans "identifier:" %} {{ event.slug }}] /
{{ event.start_datetime }}
{% if event.full %}/ <span class="full">{% trans "full" %}</span>{% endif %}
(

View File

@ -1,2 +1,2 @@
{% load i18n %}{% trans 'date' %},{% trans 'time' %},{% trans 'number of places' %},{% trans 'number of places in waiting list' %},{% trans 'label' %}
{{ some_future_date|date:"Y-m-d" }},{{ some_future_date|date:"H:i" }},15,0,{% trans "example event" %}
{% load i18n %}{% trans 'date' %},{% trans 'time' %},{% trans 'number of places' %},{% trans 'number of places in waiting list' %},{% trans 'label' %},{% trans 'identifier' %}
{{ some_future_date|date:"Y-m-d" }},{{ some_future_date|date:"H:i" }},15,0,{% trans "example event" as label %}{{ label }},{{ label|slugify }}

View File

@ -36,7 +36,7 @@ from chrono.agendas.models import (Agenda, Event, MeetingType, TimePeriod,
Booking, Desk, TimePeriodException,
ICSError, AgendaImportError)
from .forms import (AgendaAddForm, AgendaEditForm, EventForm, NewMeetingTypeForm, MeetingTypeForm,
from .forms import (AgendaAddForm, AgendaEditForm, NewEventForm, EventForm, NewMeetingTypeForm, MeetingTypeForm,
TimePeriodForm, ImportEventsForm, NewDeskForm, DeskForm, TimePeriodExceptionForm,
ExceptionsImportForm, AgendasImportForm, TimePeriodAddForm)
from .utils import import_site
@ -567,7 +567,7 @@ agenda_export = AgendaExport.as_view()
class AgendaAddEventView(ManagedAgendaMixin, CreateView):
template_name = 'chrono/manager_event_form.html'
model = Event
form_class = EventForm
form_class = NewEventForm
agenda_add_event = AgendaAddEventView.as_view()

View File

@ -123,11 +123,19 @@ def test_slug():
agenda.save()
assert agenda.slug == 'foo-bar'
event = Event.objects.create(start_datetime=now(), places=42, agenda=agenda, label='Foo bar')
assert event.slug == 'foo-bar'
def test_existing_slug():
agenda = Agenda(label=u'Foo bar', slug='bar')
agenda.save()
assert agenda.slug == 'bar'
event = Event.objects.create(start_datetime=now(), places=42, agenda=agenda, label='Foo bar', slug='bar')
assert event.slug == 'bar'
def test_duplicate_slugs():
agenda = Agenda(label=u'Foo baz')
agenda.save()
@ -139,6 +147,14 @@ def test_duplicate_slugs():
agenda.save()
assert agenda.slug == 'foo-baz-2'
event = Event.objects.create(start_datetime=now(), places=42, agenda=agenda, label='Foo bar')
assert event.slug == 'foo-bar'
event = Event.objects.create(start_datetime=now(), places=42, agenda=agenda, label='Foo bar')
assert event.slug == 'foo-bar-1'
event = Event.objects.create(start_datetime=now(), places=42, agenda=agenda, label='Foo bar')
assert event.slug == 'foo-bar-2'
def test_event_manager():
agenda = Agenda(label=u'Foo baz')
agenda.save()

View File

@ -636,6 +636,22 @@ def test_import_events(app, admin_user):
'"2016-09-19"\t"18:00"\t"10"'.encode('iso-8859-15'), 'text/csv')
resp = resp.form.submit(status=302)
assert Event.objects.count() == 2
Event.objects.all().delete()
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,label,slug', 'text/csv')
resp = resp.form.submit(status=302)
assert Event.objects.count() == 1
event = Event.objects.latest('pk')
assert event.start_datetime == make_aware(datetime.datetime(2016, 9, 16, 18, 0))
assert event.places == 10
assert event.waiting_list_places == 5
assert event.label == 'label'
assert event.slug == 'slug'
resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,label,slug', 'text/csv')
resp = resp.form.submit(status=200)
assert 'Invalid file format. (slug: Event with this Identifier already exists.' in resp.text
def test_add_meetings_agenda(app, admin_user):