Projet

Général

Profil

0001-api-add-a-field-slug-to-Event-15726.patch

Lauréline Guérin, 06 novembre 2019 18:39

Télécharger (11,9 ko)

Voir les différences:

Subject: [PATCH 1/2] api: add a field 'slug' to Event (#15726)

 chrono/agendas/migrations/0028_event_slug.py  | 37 +++++++++++++++++++
 .../migrations/0029_auto_20191106_1320.py     | 20 ++++++++++
 chrono/agendas/models.py                      | 18 +++++++++
 chrono/manager/forms.py                       | 19 +++++++++-
 .../chrono/manager_agenda_settings.html       |  2 +-
 .../chrono/manager_sample_events.txt          |  4 +-
 chrono/manager/views.py                       |  4 +-
 tests/test_agendas.py                         | 16 ++++++++
 tests/test_manager.py                         | 16 ++++++++
 9 files changed, 129 insertions(+), 7 deletions(-)
 create mode 100644 chrono/agendas/migrations/0028_event_slug.py
 create mode 100644 chrono/agendas/migrations/0029_auto_20191106_1320.py
chrono/agendas/migrations/0028_event_slug.py
1
# -*- coding: utf-8 -*-
2
from __future__ import unicode_literals
3

  
4
from django.db import migrations, models
5
from django.utils.text import slugify
6

  
7

  
8
def set_slug_on_events(apps, schema_editor):
9
    Event = apps.get_model('agendas', 'Event')
10
    for event in Event.objects.filter(slug=''):
11
        base_slug = slugify(event.label)
12
        slug = base_slug
13
        i = 1
14
        while True:
15
            if not Event.objects.filter(slug=slug).exists():
16
                break
17
            slug = '%s-%s' % (base_slug, i)
18
            i += 1
19
        event.slug = slug
20
        event.save(update_fields=['slug'])
21

  
22

  
23
class Migration(migrations.Migration):
24

  
25
    dependencies = [
26
        ('agendas', '0027_event_description'),
27
    ]
28

  
29
    operations = [
30
        migrations.AddField(
31
            model_name='event',
32
            name='slug',
33
            field=models.SlugField(default='', max_length=160, verbose_name='Identifier'),
34
            preserve_default=False,
35
        ),
36
        migrations.RunPython(set_slug_on_events, lambda x, y: None),
37
    ]
chrono/agendas/migrations/0029_auto_20191106_1320.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.18 on 2019-11-06 12:20
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations, models
6

  
7

  
8
class Migration(migrations.Migration):
9

  
10
    dependencies = [
11
        ('agendas', '0028_event_slug'),
12
    ]
13

  
14
    operations = [
15
        migrations.AlterField(
16
            model_name='event',
17
            name='slug',
18
            field=models.SlugField(max_length=160, unique=True, verbose_name='Identifier'),
19
        ),
20
    ]
chrono/agendas/models.py
289 289
            _('Places in waiting list'), default=0)
290 290
    label = models.CharField(_('Label'), max_length=150, null=True, blank=True,
291 291
            help_text=_('Optional label to identify this date.'))
292
    slug = models.SlugField(_('Identifier'), max_length=160, unique=True)
292 293
    description = models.TextField(_('Description'), null=True, blank=True,
293 294
            help_text=_('Optional event description.'))
294 295
    full = models.BooleanField(default=False)
......
305 306

  
306 307
    def save(self, *args, **kwargs):
307 308
        self.check_full()
309
        if not self.slug:
310
            base_slug = slugify(self.label)
311
            slug = base_slug
312
            i = 1
313
            while True:
314
                if not Event.objects.filter(slug=slug).exists():
315
                    break
316
                slug = '%s-%s' % (base_slug, i)
317
                i += 1
318
            self.slug = slug
308 319
        return super(Event, self).save(*args, **kwargs)
309 320

  
310 321
    def check_full(self):
......
345 356
    def import_json(cls, data):
346 357
        data['start_datetime'] = make_aware(datetime.datetime.strptime(
347 358
            data['start_datetime'], '%Y-%m-%d %H:%M:%S'))
359
        if 'slug' in data:
360
            event, created = cls.objects.get_or_create(slug=data['slug'], defaults=data)
361
            if not created:
362
                for k, v in data.items():
363
                    setattr(event, k, v)
364
            return event
348 365
        return cls(**data)
349 366

  
350 367
    def export_json(self):
......
353 370
            'places': self.places,
354 371
            'waiting_list_places': self.waiting_list_places,
355 372
            'label': self.label,
373
            'slug': self.slug,
356 374
            'description': self.description,
357 375
        }
358 376

  
chrono/manager/forms.py
63 63
        fields = ['label', 'slug', 'edit_role', 'view_role', 'minimal_booking_delay', 'maximal_booking_delay']
64 64

  
65 65

  
66
class NewEventForm(forms.ModelForm):
67
    class Meta:
68
        model = Event
69
        widgets = {
70
                'agenda': forms.HiddenInput(),
71
                'start_datetime': DateTimeWidget(),
72
        }
73
        exclude = ['full', 'meeting_type', 'desk', 'slug']
74

  
75

  
66 76
class EventForm(forms.ModelForm):
67 77
    class Meta:
68 78
        model = Event
......
220 230
                except ValueError:
221 231
                    raise ValidationError(_('Invalid file format. (number of places in waiting list, line %d)') % (i+1))
222 232
            if len(csvline) >= 5:
223
                event.label = ' '.join([force_text(x) for x in csvline[4:]])
233
                event.label = force_text(csvline[4])
234
            exclude = ['agenda', 'desk', 'meeting_type']
235
            if len(csvline) >= 6:
236
                event.slug = ' '.join([force_text(x) for x in csvline[5:]])
237
            else:
238
                exclude += ['slug']
224 239
            try:
225
                event.full_clean(exclude=['agenda', 'desk', 'meeting_type'])
240
                event.full_clean(exclude=exclude)
226 241
            except ValidationError as e:
227 242
                errors = [
228 243
                    _('Invalid file format. (%(label)s: %(errors)s, line %(line)d)') % {
chrono/manager/templates/chrono/manager_agenda_settings.html
46 46
          data-total="{{event.waiting_list_places}}" data-booked="{{event.waiting_list}}"
47 47
        {% endif %}
48 48
        ><a rel="popup" href="{% if user_can_manage %}{% url 'chrono-manager-event-edit' pk=event.id %}{% else %}#{% endif %}">
49
        {% if event.label %}{{event.label}} / {% endif %}
49
        {% if event.label %}{{event.label}} {% endif %}[{% trans "identifier:" %} {{ event.slug }}] /
50 50
        {{ event.start_datetime }}
51 51
        {% if event.full %}/ <span class="full">{% trans "full" %}</span>{% endif %}
52 52
        (
chrono/manager/templates/chrono/manager_sample_events.txt
1
{% load i18n %}{% trans 'date' %},{% trans 'time' %},{% trans 'number of places' %},{% trans 'number of places in waiting list' %},{% trans 'label' %}
2
{{ some_future_date|date:"Y-m-d" }},{{ some_future_date|date:"H:i" }},15,0,{% trans "example event" %}
1
{% load i18n %}{% trans 'date' %},{% trans 'time' %},{% trans 'number of places' %},{% trans 'number of places in waiting list' %},{% trans 'label' %},{% trans 'identifier' %}
2
{{ some_future_date|date:"Y-m-d" }},{{ some_future_date|date:"H:i" }},15,0,{% trans "example event" as label %}{{ label }},{{ label|slugify }}
chrono/manager/views.py
36 36
                                   Booking, Desk, TimePeriodException,
37 37
                                   ICSError, AgendaImportError)
38 38

  
39
from .forms import (AgendaAddForm, AgendaEditForm, EventForm, NewMeetingTypeForm, MeetingTypeForm,
39
from .forms import (AgendaAddForm, AgendaEditForm, NewEventForm, EventForm, NewMeetingTypeForm, MeetingTypeForm,
40 40
                    TimePeriodForm, ImportEventsForm, NewDeskForm, DeskForm, TimePeriodExceptionForm,
41 41
                    ExceptionsImportForm, AgendasImportForm, TimePeriodAddForm)
42 42
from .utils import import_site
......
567 567
class AgendaAddEventView(ManagedAgendaMixin, CreateView):
568 568
    template_name = 'chrono/manager_event_form.html'
569 569
    model = Event
570
    form_class = EventForm
570
    form_class = NewEventForm
571 571

  
572 572
agenda_add_event = AgendaAddEventView.as_view()
573 573

  
tests/test_agendas.py
123 123
    agenda.save()
124 124
    assert agenda.slug == 'foo-bar'
125 125

  
126
    event = Event.objects.create(start_datetime=now(), places=42, agenda=agenda, label='Foo bar')
127
    assert event.slug == 'foo-bar'
128

  
129

  
126 130
def test_existing_slug():
127 131
    agenda = Agenda(label=u'Foo bar', slug='bar')
128 132
    agenda.save()
129 133
    assert agenda.slug == 'bar'
130 134

  
135
    event = Event.objects.create(start_datetime=now(), places=42, agenda=agenda, label='Foo bar', slug='bar')
136
    assert event.slug == 'bar'
137

  
138

  
131 139
def test_duplicate_slugs():
132 140
    agenda = Agenda(label=u'Foo baz')
133 141
    agenda.save()
......
139 147
    agenda.save()
140 148
    assert agenda.slug == 'foo-baz-2'
141 149

  
150
    event = Event.objects.create(start_datetime=now(), places=42, agenda=agenda, label='Foo bar')
151
    assert event.slug == 'foo-bar'
152
    event = Event.objects.create(start_datetime=now(), places=42, agenda=agenda, label='Foo bar')
153
    assert event.slug == 'foo-bar-1'
154
    event = Event.objects.create(start_datetime=now(), places=42, agenda=agenda, label='Foo bar')
155
    assert event.slug == 'foo-bar-2'
156

  
157

  
142 158
def test_event_manager():
143 159
    agenda = Agenda(label=u'Foo baz')
144 160
    agenda.save()
tests/test_manager.py
636 636
                                                   '"2016-09-19"\t"18:00"\t"10"'.encode('iso-8859-15'), 'text/csv')
637 637
    resp = resp.form.submit(status=302)
638 638
    assert Event.objects.count() == 2
639
    Event.objects.all().delete()
640

  
641
    resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
642
    resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,label,slug', 'text/csv')
643
    resp = resp.form.submit(status=302)
644
    assert Event.objects.count() == 1
645
    event = Event.objects.latest('pk')
646
    assert event.start_datetime == make_aware(datetime.datetime(2016, 9, 16, 18, 0))
647
    assert event.places == 10
648
    assert event.waiting_list_places == 5
649
    assert event.label == 'label'
650
    assert event.slug == 'slug'
651
    resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
652
    resp.form['events_csv_file'] = Upload('t.csv', b'2016-09-16,18:00,10,5,label,slug', 'text/csv')
653
    resp = resp.form.submit(status=200)
654
    assert 'Invalid file format. (slug: Event with this Identifier already exists.' in resp.text
639 655

  
640 656

  
641 657
def test_add_meetings_agenda(app, admin_user):
642
-