Projet

Général

Profil

0001-manager-manage-recurring-events-in-csv-import-export.patch

Lauréline Guérin, 05 mars 2021 14:01

Télécharger (12,1 ko)

Voir les différences:

Subject: [PATCH] manager: manage recurring events in csv import/export
 (#51645)

 chrono/manager/forms.py                       |  22 +++-
 .../chrono/manager_sample_events.txt          |   4 +-
 chrono/manager/views.py                       |  12 +-
 tests/test_manager.py                         | 112 +++++++++++++++++-
 4 files changed, 139 insertions(+), 11 deletions(-)
chrono/manager/forms.py
500 500
        help_text=_(
501 501
            'CSV file with date, time, number of places, '
502 502
            'number of places in waiting list, label, and '
503
            'optionally, identifier, description, pricing, '
504
            'URL, and publication date as columns.'
503
            'optionally, identifier, description, pricing,<br />'
504
            'URL, publication date, duration, recurrence repetition '
505
            'and recurrence end date as columns.'
505 506
        ),
506 507
    )
507 508
    events = None
......
631 632
                except ValueError:
632 633
                    raise ValidationError(_('Invalid file format. (duration, line %d)') % (i + 1))
633 634

  
635
            if len(csvline) >= 12 and csvline[11]:  # recurrence repetition is optional
636
                if csvline[11] not in [k for k, v in Event.REPEAT_CHOICES]:
637
                    raise ValidationError(
638
                        _('Invalid file format. (recurrence repetition, line %d)') % (i + 1)
639
                    )
640
                event.repeat = csvline[11]
641

  
642
            if len(csvline) >= 13 and csvline[12]:  # recurrence_end_date is optional
643
                for date_fmt in ('%Y-%m-%d', '%d/%m/%Y'):
644
                    try:
645
                        event.recurrence_end_date = datetime.datetime.strptime(csvline[12], date_fmt).date()
646
                        break
647
                    except ValueError:
648
                        continue
649
                else:
650
                    raise ValidationError(_('Invalid file format. (date format, line %d)') % (i + 1))
651

  
634 652
            try:
635 653
                event.full_clean(exclude=['desk', 'meeting_type', 'primary_event'])
636 654
            except ValidationError as e:
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' %},{% trans 'identifier' %},{% trans 'description' %},{% trans 'pricing' %},{% trans 'URL' %},{% trans 'publication date' %},{% trans 'duration' %}
2
{{ some_future_date|date:"Y-m-d" }},{{ some_future_date|date:"H:i" }},15,0,{% trans "example event" as label %}{{ label }},{{ label|slugify }},,,https://www.example.net,{{ some_future_date|date:"Y-m-d" }},30
1
{% load i18n %}{% trans 'date' %},{% trans 'time' %},{% trans 'number of places' %},{% trans 'number of places in waiting list' %},{% trans 'label' %},{% trans 'identifier' %},{% trans 'description' %},{% trans 'pricing' %},{% trans 'URL' %},{% trans 'publication date' %},{% trans 'duration' %},{% trans 'recurrence repetition' %},{% trans 'recurrence end date' %}
2
{{ some_future_date|date:"Y-m-d" }},{{ some_future_date|date:"H:i" }},15,0,{% trans "example event" as label %}{{ label }},{{ label|slugify }},,,https://www.example.net,{{ some_future_date|date:"Y-m-d" }},30,daily,{{ some_future_date|date:"Y-m-d" }}
chrono/manager/views.py
1484 1484
            for event in form.events:
1485 1485
                event.agenda = self.agenda
1486 1486
                event.save()
1487
                if event.recurrence_rule and event.recurrence_end_date:
1488
                    event.recurrences.filter(start_datetime__gt=event.recurrence_end_date).delete()
1489
                    excluded_datetimes = [
1490
                        make_naive(dt) for dt in event.recurrences.values_list('start_datetime', flat=True)
1491
                    ]
1492
                    event.create_all_recurrences(excluded_datetimes)
1487 1493
            messages.info(self.request, _('%d events have been imported.') % len(form.events))
1488 1494
            for event in form.warnings.values():
1489 1495
                messages.warning(
......
1525 1531
                _('URL'),
1526 1532
                _('publication date'),
1527 1533
                _('duration'),
1534
                _('recurrence repetition'),
1535
                _('recurrence end date'),
1528 1536
            ]
1529 1537
        )
1530
        for event in self.agenda.event_set.all():
1538
        for event in self.agenda.event_set.filter(primary_event__isnull=True):
1531 1539
            start_datetime = localtime(event.start_datetime)
1532 1540
            writer.writerow(
1533 1541
                [
......
1542 1550
                    event.url,
1543 1551
                    event.publication_date.strftime('%Y-%m-%d') if event.publication_date else '',
1544 1552
                    event.duration,
1553
                    event.repeat,
1554
                    event.recurrence_end_date.strftime('%Y-%m-%d') if event.recurrence_end_date else '',
1545 1555
                ]
1546 1556
            )
1547 1557
        return response
tests/test_manager.py
21 21
import freezegun
22 22
import pytest
23 23
import requests
24
from dateutil.rrule import DAILY
24 25
from webtest import Upload
25 26

  
26 27
from chrono.agendas.models import (
......
1720 1721
    csv_export = resp.text
1721 1722
    assert (
1722 1723
        csv_export
1723
        == 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date,duration\r\n'
1724
        == 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,'
1725
        'publication date,duration,recurrence repetition,recurrence end date\r\n'
1724 1726
    )
1725 1727

  
1726 1728
    resp = app.get('/manage/agendas/%s/import-events' % agenda.id)
......
1731 1733
    csv_export = resp.text
1732 1734
    assert (
1733 1735
        csv_export
1734
        == 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date,duration\r\n'
1735
        '2016-09-16,00:30,10,0,,foo-bar-event,,,,,\r\n'
1736
        == 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,'
1737
        'publication date,duration,recurrence repetition,recurrence end date\r\n'
1738
        '2016-09-16,00:30,10,0,,foo-bar-event,,,,,,,\r\n'
1736 1739
    )
1737 1740

  
1738 1741
    resp = app.get('/manage/agendas/%s/import-events' % agenda.id)
......
1746 1749
    csv_export = resp.text
1747 1750
    assert (
1748 1751
        csv_export
1749
        == 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date,duration\r\n'
1750
        '2016-09-16,00:30,10,0,,foo-bar-event,,,,,\r\n'
1751
        '2016-09-16,23:30,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16,90\r\n'
1752
        == 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,'
1753
        'publication date,duration,recurrence repetition,recurrence end date\r\n'
1754
        '2016-09-16,00:30,10,0,,foo-bar-event,,,,,,,\r\n'
1755
        '2016-09-16,23:30,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16,90,,\r\n'
1752 1756
    )
1753 1757

  
1754 1758

  
......
2083 2087
    )
2084 2088

  
2085 2089

  
2090
@pytest.mark.freeze_time('2021-01-12 12:10')
2091
def test_import_events_recurring_event(app, admin_user):
2092
    agenda = Agenda.objects.create(label=u'Foo bar', kind='events')
2093
    event = Event.objects.create(
2094
        agenda=agenda,
2095
        start_datetime=now(),
2096
        repeat='daily',
2097
        places=10,
2098
        slug='test',
2099
    )
2100
    event.get_or_create_event_recurrence(event.start_datetime + datetime.timedelta(days=3))
2101
    assert Event.objects.count() == 2
2102

  
2103
    app = login(app)
2104
    resp = app.get('/manage/agendas/%s/export-events' % agenda.pk)
2105
    csv_export = resp.text
2106
    assert csv_export == (
2107
        'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,'
2108
        'publication date,duration,recurrence repetition,recurrence end date\r\n'
2109
        '2021-01-12,13:10,10,0,,test,,,,,,daily,\r\n'
2110
    )
2111
    Event.objects.all().delete()
2112

  
2113
    resp = app.get('/manage/agendas/%s/import-events' % agenda.pk)
2114
    resp.form['events_csv_file'] = Upload('t.csv', b'2021-01-12,13:10,10,0,,test,,,,,,daily,', 'text/csv')
2115
    resp.form.submit(status=302)
2116
    assert Event.objects.count() == 1
2117
    event = Event.objects.first()
2118
    assert event.start_datetime == make_aware(datetime.datetime(2021, 1, 12, 13, 10))
2119
    assert event.places == 10
2120
    assert event.waiting_list_places == 0
2121
    assert event.primary_event is None
2122
    assert event.repeat == 'daily'
2123
    assert event.recurrence_rule == {'freq': DAILY}
2124
    assert event.recurrence_end_date is None
2125
    Event.objects.all().delete()
2126

  
2127
    # wrong repeat format
2128
    resp = app.get('/manage/agendas/%s/import-events' % agenda.pk)
2129
    resp.form['events_csv_file'] = Upload('t.csv', b'2021-01-12,13:10,10,0,,test,,,,,,foobar,', 'text/csv')
2130
    resp = resp.form.submit(status=200)
2131
    assert 'Invalid file format. (recurrence repetition' in resp.text
2132
    assert Event.objects.count() == 0
2133

  
2134
    # check recurrence_end_date
2135
    event = Event.objects.create(
2136
        agenda=agenda,
2137
        start_datetime=now(),
2138
        repeat='daily',
2139
        recurrence_end_date=now() + datetime.timedelta(days=7),
2140
        places=10,
2141
        slug='test',
2142
    )
2143
    event.create_all_recurrences()
2144
    assert Event.objects.filter(primary_event=event).count() == 7
2145

  
2146
    resp = app.get('/manage/agendas/%s/export-events' % agenda.pk)
2147
    csv_export = resp.text
2148
    assert csv_export == (
2149
        'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,'
2150
        'publication date,duration,recurrence repetition,recurrence end date\r\n'
2151
        '2021-01-12,13:10,10,0,,test,,,,,,daily,2021-01-19\r\n'
2152
    )
2153
    Event.objects.all().delete()
2154

  
2155
    resp = app.get('/manage/agendas/%s/import-events' % agenda.pk)
2156
    resp.form['events_csv_file'] = Upload(
2157
        't.csv', b'2021-01-12,13:10,10,0,,test,,,,,,daily,2021-01-19', 'text/csv'
2158
    )
2159
    resp.form.submit(status=302)
2160
    event = Event.objects.get(slug='test')
2161
    assert Event.objects.count() == 8
2162
    assert Event.objects.filter(primary_event=event).count() == 7
2163

  
2164
    # import again
2165
    resp = app.get('/manage/agendas/%s/import-events' % agenda.pk)
2166
    resp.form['events_csv_file'] = Upload(
2167
        't.csv', b'2021-01-12,13:10,10,0,,test,,,,,,daily,2021-01-19', 'text/csv'
2168
    )
2169
    resp.form.submit(status=302)
2170
    event = Event.objects.get(slug='test')
2171
    assert Event.objects.count() == 8
2172
    assert Event.objects.filter(primary_event=event).count() == 7
2173

  
2174
    Event.objects.all().delete()
2175

  
2176
    # wrong recurrence_end_date format
2177
    resp = app.get('/manage/agendas/%s/import-events' % agenda.pk)
2178
    resp.form['events_csv_file'] = Upload(
2179
        't.csv', b'2021-01-12,13:10,10,0,,test,,,,,,daily,foobar', 'text/csv'
2180
    )
2181
    resp = resp.form.submit(status=200)
2182
    assert 'Invalid file format. (date format' in resp.text
2183
    assert Event.objects.count() == 0
2184

  
2185

  
2086 2186
def test_import_events_wrong_kind(app, admin_user):
2087 2187
    agenda = Agenda.objects.create(label=u'Foo bar', kind='meetings')
2088 2188

  
2089
-