Projet

Général

Profil

0001-agendas-event-publication_datetime-56634.patch

Lauréline Guérin, 09 octobre 2021 09:18

Télécharger (34,8 ko)

Voir les différences:

Subject: [PATCH] agendas: event publication_datetime (#56634)

 .../migrations/0101_publication_datetime.py   | 16 +++++
 .../migrations/0102_publication_datetime.py   | 31 ++++++++++
 .../migrations/0103_publication_datetime.py   | 15 +++++
 chrono/agendas/models.py                      | 24 ++++----
 chrono/api/serializers.py                     |  2 +-
 chrono/api/views.py                           |  2 +-
 chrono/manager/forms.py                       | 22 +++++--
 .../chrono/manager_agenda_event_fragment.html |  4 +-
 .../chrono/manager_event_detail_fragment.html |  2 +-
 .../chrono/manager_sample_events.txt          |  4 +-
 chrono/manager/views.py                       |  7 ++-
 tests/api/test_all.py                         |  4 +-
 tests/api/test_datetimes.py                   | 12 ++--
 tests/api/test_event.py                       | 12 ++--
 tests/manager/test_all.py                     |  8 +--
 tests/manager/test_event.py                   | 59 +++++++++++++------
 tests/test_agendas.py                         |  4 +-
 tests/test_import_export.py                   |  5 +-
 18 files changed, 169 insertions(+), 64 deletions(-)
 create mode 100644 chrono/agendas/migrations/0101_publication_datetime.py
 create mode 100644 chrono/agendas/migrations/0102_publication_datetime.py
 create mode 100644 chrono/agendas/migrations/0103_publication_datetime.py
chrono/agendas/migrations/0101_publication_datetime.py
1
from django.db import migrations, models
2

  
3

  
4
class Migration(migrations.Migration):
5

  
6
    dependencies = [
7
        ('agendas', '0100_event_dml'),
8
    ]
9

  
10
    operations = [
11
        migrations.AddField(
12
            model_name='event',
13
            name='publication_datetime',
14
            field=models.DateTimeField(blank=True, null=True, verbose_name='Publication date/time'),
15
        ),
16
    ]
chrono/agendas/migrations/0102_publication_datetime.py
1
import datetime
2

  
3
from django.db import migrations
4
from django.utils.timezone import localtime, make_aware
5

  
6

  
7
def forwards(apps, schema_editor):
8
    Event = apps.get_model('agendas', 'Event')
9
    for event in Event.objects.filter(publication_date__isnull=False):
10
        event.publication_datetime = make_aware(
11
            datetime.datetime.combine(event.publication_date, datetime.time(0, 0))
12
        )
13
        event.save()
14

  
15

  
16
def backwards(apps, schema_editor):
17
    Event = apps.get_model('agendas', 'Event')
18
    for event in Event.objects.filter(publication_datetime__isnull=False):
19
        event.publication_date = localtime(event.publication_datetime).date()
20
        event.save()
21

  
22

  
23
class Migration(migrations.Migration):
24

  
25
    dependencies = [
26
        ('agendas', '0101_publication_datetime'),
27
    ]
28

  
29
    operations = [
30
        migrations.RunPython(forwards, reverse_code=backwards),
31
    ]
chrono/agendas/migrations/0103_publication_datetime.py
1
from django.db import migrations
2

  
3

  
4
class Migration(migrations.Migration):
5

  
6
    dependencies = [
7
        ('agendas', '0102_publication_datetime'),
8
    ]
9

  
10
    operations = [
11
        migrations.RemoveField(
12
            model_name='event',
13
            name='publication_date',
14
        ),
15
    ]
chrono/agendas/models.py
133 133
def event_template_validator(value):
134 134
    example_event = Event(
135 135
        start_datetime=now(),
136
        publication_date=now().date(),
136
        publication_datetime=now(),
137 137
        recurrence_end_date=now().date(),
138 138
        places=1,
139 139
        duration=1,
......
666 666
            entries = entries.filter(start_datetime__gte=localtime(now()))
667 667
            # exclude non published events
668 668
            entries = entries.filter(
669
                Q(publication_date__isnull=True) | Q(publication_date__lte=localtime(now()).date())
669
                Q(publication_datetime__isnull=True) | Q(publication_datetime__lte=now())
670 670
            )
671 671
            if not include_full:
672 672
                entries = entries.filter(Q(full=False) | Q(primary_event__isnull=False))
......
745 745

  
746 746
    def get_open_recurring_events(self):
747 747
        return self.event_set.filter(
748
            Q(publication_date__isnull=True) | Q(publication_date__lte=localtime(now()).date()),
748
            Q(publication_datetime__isnull=True) | Q(publication_datetime__lte=now()),
749 749
            recurrence_days__isnull=False,
750 750
            recurrence_end_date__gt=localtime(now()).date(),
751 751
        )
......
773 773
            exceptions = self.prefetched_exceptions
774 774
        else:
775 775
            recurring_events = self.event_set.filter(
776
                Q(publication_date__isnull=True) | Q(publication_date__lte=localtime(now()).date()),
776
                Q(publication_datetime__isnull=True) | Q(publication_datetime__lte=now()),
777 777
                recurrence_days__isnull=False,
778 778
            )
779 779
            exceptions = self.get_recurrence_exceptions(min_start, max_start)
......
884 884
        qs, user_external_id=None, show_past_events=False, min_start=None, max_start=None
885 885
    ):
886 886
        event_queryset = Event.objects.filter(
887
            Q(publication_date__isnull=True) | Q(publication_date__lte=localtime(now()).date()),
887
            Q(publication_datetime__isnull=True) | Q(publication_datetime__lte=now()),
888 888
            recurrence_days__isnull=True,
889 889
            cancelled=False,
890 890
        ).order_by()
......
899 899
            event_queryset = event_queryset.filter(start_datetime__lt=max_start)
900 900

  
901 901
        recurring_event_queryset = Event.objects.filter(
902
            Q(publication_date__isnull=True) | Q(publication_date__lte=localtime(now()).date()),
902
            Q(publication_datetime__isnull=True) | Q(publication_datetime__lte=now()),
903 903
            recurrence_days__isnull=False,
904 904
        )
905 905
        exceptions_desk = Desk.objects.filter(slug='_exceptions_holder').prefetch_related(
......
1355 1355
    recurrence_end_date = models.DateField(_('Recurrence end date'), null=True, blank=True)
1356 1356
    primary_event = models.ForeignKey('self', null=True, on_delete=models.CASCADE, related_name='recurrences')
1357 1357
    duration = models.PositiveIntegerField(_('Duration (in minutes)'), default=None, null=True, blank=True)
1358
    publication_date = models.DateField(_('Publication date'), blank=True, null=True)
1358
    publication_datetime = models.DateTimeField(_('Publication date/time'), blank=True, null=True)
1359 1359
    places = models.PositiveIntegerField(_('Places'))
1360 1360
    waiting_list_places = models.PositiveIntegerField(_('Places in waiting list'), default=0)
1361 1361
    label = models.CharField(
......
1451 1451
        self.save(update_fields=['checked'])
1452 1452

  
1453 1453
    def in_bookable_period(self):
1454
        if self.publication_date and localtime(now()).date() < self.publication_date:
1454
        if self.publication_datetime and now() < self.publication_datetime:
1455 1455
            return False
1456 1456
        if self.agenda.maximal_booking_delay and self.start_datetime > self.agenda.max_booking_datetime:
1457 1457
            return False
......
1545 1545
                for field in [
1546 1546
                    'label',
1547 1547
                    'duration',
1548
                    'publication_date',
1548
                    'publication_datetime',
1549 1549
                    'places',
1550 1550
                    'waiting_list_places',
1551 1551
                    'description',
......
1565 1565
        )
1566 1566
        return {
1567 1567
            'start_datetime': make_naive(self.start_datetime).strftime('%Y-%m-%d %H:%M:%S'),
1568
            'publication_date': self.publication_date.strftime('%Y-%m-%d') if self.publication_date else None,
1568
            'publication_datetime': make_naive(self.publication_datetime).strftime('%Y-%m-%d %H:%M:%S')
1569
            if self.publication_datetime
1570
            else None,
1569 1571
            'recurrence_days': self.recurrence_days,
1570 1572
            'recurrence_week_interval': self.recurrence_week_interval,
1571 1573
            'recurrence_end_date': recurrence_end_date,
......
1659 1661
            duration=self.duration,
1660 1662
            places=self.places,
1661 1663
            waiting_list_places=self.waiting_list_places,
1662
            publication_date=self.publication_date,
1664
            publication_datetime=self.publication_datetime,
1663 1665
            label=self.label,
1664 1666
            description=self.description,
1665 1667
            pricing=self.pricing,
chrono/api/serializers.py
150 150
            'recurrence_week_interval',
151 151
            'recurrence_end_date',
152 152
            'duration',
153
            'publication_date',
153
            'publication_datetime',
154 154
            'places',
155 155
            'waiting_list_places',
156 156
            'label',
chrono/api/views.py
2259 2259
            for field in changed_data:
2260 2260
                if field in (
2261 2261
                    'recurrence_end_date',
2262
                    'publication_date',
2262
                    'publication_datetime',
2263 2263
                    'recurrence_days',
2264 2264
                    'recurrence_week_interval',
2265 2265
                ):
chrono/manager/forms.py
216 216
    class Meta:
217 217
        model = Event
218 218
        widgets = {
219
            'publication_date': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
220 219
            'recurrence_end_date': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
221 220
        }
222 221
        fields = [
......
228 227
            'recurrence_week_interval',
229 228
            'recurrence_end_date',
230 229
            'duration',
231
            'publication_date',
230
            'publication_datetime',
232 231
            'places',
233 232
            'waiting_list_places',
234 233
            'description',
......
237 236
        ]
238 237
        field_classes = {
239 238
            'start_datetime': SplitDateTimeField,
239
            'publication_datetime': SplitDateTimeField,
240 240
        }
241 241

  
242 242
    def __init__(self, *args, **kwargs):
......
252 252
            for field in (
253 253
                'slug',
254 254
                'recurrence_end_date',
255
                'publication_date',
255
                'publication_datetime',
256 256
                'frequency',
257 257
                'recurrence_days',
258 258
                'recurrence_week_interval',
......
706 706
                column_index += 1
707 707

  
708 708
            if len(csvline) >= 10 and csvline[9]:  # publication date is optional
709
                for date_fmt in ('%Y-%m-%d', '%d/%m/%Y'):
709
                for datetime_fmt in (
710
                    '%Y-%m-%d',
711
                    '%d/%m/%Y',
712
                    '%Y-%m-%d %H:%M',
713
                    '%d/%m/%Y %H:%M',
714
                    '%d/%m/%Y %Hh%M',
715
                    '%Y-%m-%d %H:%M:%S',
716
                    '%d/%m/%Y %H:%M:%S',
717
                ):
710 718
                    try:
711
                        event.publication_date = datetime.datetime.strptime(csvline[9], date_fmt).date()
719
                        event.publication_datetime = make_aware(
720
                            datetime.datetime.strptime(csvline[9], datetime_fmt)
721
                        )
712 722
                        break
713 723
                    except ValueError:
714 724
                        continue
715 725
                else:
716
                    raise ValidationError(_('Invalid file format. (date format, line %d)') % (i + 1))
726
                    raise ValidationError(_('Invalid file format. (date/time format, line %d)') % (i + 1))
717 727

  
718 728
            if len(csvline) >= 11 and csvline[10]:  # duration is optional
719 729
                try:
chrono/manager/templates/chrono/manager_agenda_event_fragment.html
43 43
      {% blocktrans with places=event.waiting_list_places count booked_places=event.booked_waiting_list_places %}{{ booked_places }}/{{ places }} booking{% plural %}{{ booked_places }}/{{ places }} bookings{% endblocktrans %})
44 44
    {% endif %}
45 45
    {% endif %}
46
    {% if view_mode == 'settings_view' and event.publication_date %}
47
    ({% trans "publication date:" %} {{ event.publication_date }})
46
    {% if view_mode == 'settings_view' and event.publication_datetime %}
47
    ({% trans "publication date:" %} {{ event.publication_datetime }})
48 48
    {% endif %}
49 49
    {% if not event.in_bookable_period %}
50 50
    ({% trans "out of bookable period" %})
chrono/manager/templates/chrono/manager_event_detail_fragment.html
5 5
 {% if object.description %}{{ object.description|linebreaks }}{% endif %}
6 6
 {% if object.pricing %}<p>{% trans "Pricing:" %} {{ object.pricing }}</p>{% endif %}
7 7
 {% if object.url %}<p><a href="{{ object.url }}">{{ object.url|truncatechars:100 }}</a></p>{% endif %}
8
 {% if object.publication_date %}<p>{% trans "Publication date:" %} {{ object.publication_date }}</p>{% endif %}
8
 {% if object.publication_datetime %}<p>{% trans "Publication date:" %} {{ object.publication_datetime }}</p>{% endif %}
9 9
</div>
10 10
</div>
11 11
{% endif %}
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/time' %},{% 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 H:i" }},30
chrono/manager/views.py
1804 1804
                _('description'),
1805 1805
                _('pricing'),
1806 1806
                _('URL'),
1807
                _('publication date'),
1807
                _('publication date/time'),
1808 1808
                _('duration'),
1809 1809
            ]
1810 1810
        )
1811 1811
        for event in self.agenda.event_set.all():
1812 1812
            start_datetime = localtime(event.start_datetime)
1813
            publication_datetime = (
1814
                localtime(event.publication_datetime) if event.publication_datetime else None
1815
            )
1813 1816
            writer.writerow(
1814 1817
                [
1815 1818
                    start_datetime.strftime('%Y-%m-%d'),
......
1821 1824
                    event.description,
1822 1825
                    event.pricing,
1823 1826
                    event.url,
1824
                    event.publication_date.strftime('%Y-%m-%d') if event.publication_date else '',
1827
                    publication_datetime.strftime('%Y-%m-%d %H:%M') if publication_datetime else '',
1825 1828
                    event.duration,
1826 1829
                ]
1827 1830
            )
tests/api/test_all.py
255 255
    event2.booking_set.all().delete()
256 256
    event2.refresh_from_db()
257 257
    assert event2.full is False
258
    event_agenda.event_set.update(publication_date=now().date() + datetime.timedelta(days=20))
258
    event_agenda.event_set.update(publication_datetime=now() + datetime.timedelta(days=20))
259 259
    assert list(event_agenda.get_open_events()) == []
260 260
    resp = app.get('/api/agenda/', params={'with_open_events': '1'})
261 261
    assert len(resp.json['data']) == 0
......
470 470
    event2.booking_set.all().delete()
471 471
    event2.refresh_from_db()
472 472
    assert event2.full is False
473
    agenda.event_set.update(publication_date=now().date() + datetime.timedelta(days=20))
473
    agenda.event_set.update(publication_datetime=now() + datetime.timedelta(days=20))
474 474
    resp = app.get('/api/agenda/%s/' % agenda.slug)
475 475
    assert list(agenda.get_open_events()) == []
476 476
    assert resp.json['data']['opened_events_available'] is False
tests/api/test_datetimes.py
50 50
    check_bookability(resp.json['data'])
51 51
    assert resp.json['data'][0]['description'] is None
52 52

  
53
    agenda.event_set.update(publication_date=localtime(now()).date() + datetime.timedelta(days=1))
53
    agenda.event_set.update(publication_datetime=now() + datetime.timedelta(minutes=1))
54 54
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
55 55
    assert len(resp.json['data']) == 0
56 56
    check_bookability(resp.json['data'])
57 57

  
58
    agenda.event_set.update(publication_date=localtime(now()).date())
58
    agenda.event_set.update(publication_datetime=now())
59 59
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
60 60
    assert len(resp.json['data']) == 2
61 61
    check_bookability(resp.json['data'])
......
662 662

  
663 663
    # publication date is accounted for
664 664
    Event.objects.filter(primary_event=base_event).delete()
665
    base_event.publication_date = now().replace(day=27)
665
    base_event.publication_datetime = now().replace(day=27)
666 666
    base_event.save()
667 667
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
668 668
    assert len(resp.json['data']) == 0
669 669

  
670 670
    # events follow agenda display template
671
    Event.objects.all().update(publication_date=None)
671
    Event.objects.all().update(publication_datetime=None)
672 672
    agenda.event_display_template = '{{ event.label }} - {{ event.start_datetime }}'
673 673
    agenda.save()
674 674
    resp = app.get('/api/agenda/%s/datetimes/' % agenda.slug)
......
677 677
    # check querysets
678 678
    agenda.event_display_template = ''
679 679
    agenda.save()
680
    base_event.publication_date = None
680
    base_event.publication_datetime = None
681 681
    base_event.recurrence_end_date = datetime.date.today() + datetime.timedelta(days=365)
682 682
    base_event.save()
683 683
    base_event.create_all_recurrences()
......
1356 1356
    assert resp.json['data'][3]['id'] == 'other:1'
1357 1357
    assert resp.json['data'][3]['text'] == 'Tuesday: Other'
1358 1358

  
1359
    event.publication_date = now() + datetime.timedelta(days=2)
1359
    event.publication_datetime = now() + datetime.timedelta(days=2)
1360 1360
    event.save()
1361 1361
    resp = app.get('/api/agenda/%s/recurring-events/' % agenda.slug)
1362 1362
    assert len(resp.json['data']) == 1
tests/api/test_event.py
224 224
    assert str(event.start_datetime) == '2021-11-15 14:38:00+00:00'
225 225
    assert str(event.start_datetime.tzinfo) == 'UTC'
226 226
    assert event.places == 10
227
    assert event.publication_date is None
227
    assert event.publication_datetime is None
228 228

  
229 229
    # add with almost all optional managed fields
230 230
    params = {
231 231
        'start_datetime': '2021-11-15 15:38',
232 232
        'duration': 42,
233
        'publication_date': '2021-09-20',
233
        'publication_datetime': '2021-09-20 10:00',
234 234
        'places': 11,
235 235
        'waiting_list_places': 3,
236 236
        'label': 'FOO camp',
......
252 252
    assert event.description == 'An event'
253 253
    assert event.pricing == 'free'
254 254
    assert event.url == 'http://example.org/foo/bar/?'
255
    assert str(event.publication_datetime) == '2021-09-20 08:00:00+00:00'
256
    assert str(event.publication_datetime.tzinfo) == 'UTC'
255 257

  
256 258
    # add with errors in recurrence_days list
257 259
    params = {
......
389 391
    params = {
390 392
        'start_datetime': '2021-11-15 15:38',
391 393
        'duration': 42,
392
        'publication_date': '2021-09-20',
394
        'publication_datetime': '2021-09-20 12:00',
393 395
        'places': 8,
394 396
        'waiting_list_places': 3,
395 397
        'label': 'FOO camp',
......
407 409
    assert event.description == 'An event'
408 410
    assert event.pricing == 'free'
409 411
    assert event.url == 'http://example.org/foo/bar/?'
412
    assert str(event.publication_datetime) == '2021-09-20 10:00:00+00:00'
413
    assert str(event.publication_datetime.tzinfo) == 'UTC'
410 414

  
411 415
    # update event as a recurring event
412 416
    params = {
......
448 452

  
449 453
    # try to update protected fields of one of the event recurrencies
450 454
    params = {
451
        'publication_date': '2021-11-15',
455
        'publication_datetime': '2021-11-15 12:00',
452 456
    }
453 457
    resp = app.patch(recurrence_url, params=params, status=400)
454 458
    assert resp.json['err']
tests/manager/test_all.py
1553 1553
        agenda=agenda,
1554 1554
        label='event E',
1555 1555
        start_datetime=now() + datetime.timedelta(days=3),
1556
        publication_date=today + datetime.timedelta(days=1),
1556
        publication_datetime=now() + datetime.timedelta(days=1),
1557 1557
        places=42,
1558 1558
    )
1559 1559
    # publication date in past
......
1561 1561
        agenda=agenda,
1562 1562
        label='event F',
1563 1563
        start_datetime=now() + datetime.timedelta(days=3),
1564
        publication_date=today - datetime.timedelta(days=1),
1564
        publication_datetime=now() - datetime.timedelta(days=1),
1565 1565
        places=42,
1566 1566
    )
1567 1567
    # weekly recurring event, first recurrence is in the past but second is in range
......
1591 1591
        agenda=agenda,
1592 1592
        label='event H',
1593 1593
        start_datetime=now().replace(year=today.year + 2, month=1, day=15),
1594
        publication_date=today - datetime.timedelta(days=1),
1594
        publication_datetime=now() - datetime.timedelta(days=1),
1595 1595
        places=42,
1596 1596
    )
1597 1597
    start_datetime = localtime(now().replace(year=today.year + 2, month=2, day=1)).replace(hour=0, minute=0)
......
1599 1599
        agenda=agenda,
1600 1600
        label='event H',
1601 1601
        start_datetime=start_datetime,
1602
        publication_date=today - datetime.timedelta(days=1),
1602
        publication_datetime=now() - datetime.timedelta(days=1),
1603 1603
        places=42,
1604 1604
    )
1605 1605
    resp = app.get('/manage/agendas/%s/events/open/' % agenda.pk)
tests/manager/test_event.py
33 33
    resp = resp.form.submit()
34 34
    resp = resp.follow()
35 35
    event = Event.objects.get(places=10)
36
    assert event.publication_date is None
36
    assert event.publication_datetime is None
37 37
    assert "This agenda doesn't have any event yet." not in resp.text
38 38
    assert '/manage/agendas/%s/events/%s/' % (agenda.id, event.id) in resp.text
39 39
    assert ('Feb. 15, %s, 5 p.m.' % year) in resp.text
......
137 137
    resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.pk, event.pk))
138 138
    assert resp.form['start_datetime_0'].value == '2016-02-15'
139 139
    assert resp.form['start_datetime_1'].value == '17:00'
140
    assert resp.form['publication_date'].value == ''
140
    assert resp.form['publication_datetime_0'].value == ''
141
    assert resp.form['publication_datetime_1'].value == ''
141 142
    assert resp.form['duration'].value == ''
142 143
    assert resp.form['description'].value == ''
143 144
    resp.form['start_datetime_0'] = '2016-02-16'
144 145
    resp.form['start_datetime_1'] = '17:00'
145
    resp.form['publication_date'] = '2020-05-11'
146
    resp.form['publication_datetime_0'] = '2020-05-11'
147
    resp.form['publication_datetime_1'] = '12:00'
146 148
    resp.form['duration'].value = 45
147 149
    resp.form['places'] = 20
148 150
    resp.form['description'] = 'A description'
......
153 155
    assert 'Feb. 16, 2016, 5 p.m.' in resp.text
154 156
    event.refresh_from_db()
155 157
    assert event.places == 20
156
    assert event.publication_date == datetime.date(2020, 5, 11)
158
    assert str(event.publication_datetime) == '2020-05-11 10:00:00+00:00'
159
    assert str(event.publication_datetime.tzinfo) == 'UTC'
157 160
    assert event.duration == 45
158 161
    assert event.end_datetime == event.start_datetime + datetime.timedelta(minutes=45)
159 162
    assert event.description == 'A description'
......
193 196
        start_datetime=make_aware(datetime.datetime(2016, 2, 15, 17, 0)),
194 197
        places=20,
195 198
        agenda=agenda,
196
        publication_date=datetime.date(2020, 5, 11),
199
        publication_datetime=make_aware(datetime.datetime(2020, 5, 11)),
197 200
    )
198 201
    app = login(app, username='manager', password='manager')
199 202
    resp = app.get('/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id), status=403)
......
204 207
    resp = resp.click('Feb. 15, 2016, 5 p.m.')
205 208
    assert resp.form['start_datetime_0'].value == '2016-02-15'
206 209
    assert resp.form['start_datetime_1'].value == '17:00'
207
    assert resp.form['publication_date'].value == '2020-05-11'
210
    assert resp.form['publication_datetime_0'].value == '2020-05-11'
211
    assert resp.form['publication_datetime_1'].value == '00:00'
208 212
    resp.form['start_datetime_0'] = '2016-02-16'
209 213
    resp.form['start_datetime_1'] = '17:00'
210
    resp.form['publication_date'] = ''
214
    resp.form['publication_datetime_0'] = ''
215
    resp.form['publication_datetime_1'] = ''
211 216
    resp.form['places'] = 20
212 217
    resp = resp.form.submit()
213 218
    resp = resp.follow()
214 219
    assert '/manage/agendas/%s/events/%s/edit' % (agenda.id, event.id) in resp.text
215 220
    assert 'Feb. 16, 2016, 5 p.m.' in resp.text
216 221
    event.refresh_from_db()
217
    assert event.publication_date is None
222
    assert event.publication_datetime is None
218 223

  
219 224

  
220 225
def test_edit_recurring_event(settings, app, admin_user, freezer):
......
301 306
        'recurrence_days',
302 307
        'recurence_weekly_interval',
303 308
        'recurrence_end_date',
304
        'publication_date',
309
        'publication_datetime_0',
310
        'publication_datetime_1',
305 311
    }.isdisjoint(resp.form.fields)
306 312

  
307 313

  
......
537 543
    csv_export = resp.text
538 544
    assert (
539 545
        csv_export
540
        == 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date,duration\r\n'
546
        == 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date/time,duration\r\n'
541 547
    )
542 548

  
543 549
    resp = app.get('/manage/agendas/%s/import-events' % agenda.id)
......
548 554
    csv_export = resp.text
549 555
    assert (
550 556
        csv_export
551
        == 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date,duration\r\n'
557
        == 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date/time,duration\r\n'
552 558
        '2016-09-16,00:30,10,0,,foo-bar-event,,,,,\r\n'
553 559
    )
554 560

  
555 561
    resp = app.get('/manage/agendas/%s/import-events' % agenda.id)
556 562
    resp.form['events_csv_file'] = Upload(
557 563
        't.csv',
558
        b'2016-09-16,23:30,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16,90',
564
        b'2016-09-16,23:30,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16 00:00,90',
559 565
        'text/csv',
560 566
    )
561 567
    resp.form.submit(status=302)
......
563 569
    csv_export = resp.text
564 570
    assert (
565 571
        csv_export
566
        == 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date,duration\r\n'
572
        == 'date,time,number of places,number of places in waiting list,label,identifier,description,pricing,URL,publication date/time,duration\r\n'
567 573
        '2016-09-16,00:30,10,0,,foo-bar-event,,,,,\r\n'
568
        '2016-09-16,23:30,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16,90\r\n'
574
        '2016-09-16,23:30,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16 00:00,90\r\n'
569 575
    )
570 576

  
571 577

  
......
738 744
    assert event.description == ''
739 745
    assert event.pricing == ''
740 746
    assert event.url == ''
741
    assert event.publication_date is None
747
    assert event.publication_datetime is None
742 748
    assert event.duration is None
743 749
    Event.objects.all().delete()
744 750
    resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
......
753 759
    assert event.description == 'description\nfoobar'
754 760
    assert event.pricing == 'pricing'
755 761
    assert event.url == 'url'
756
    assert event.publication_date == datetime.date(2016, 10, 16)
762
    assert str(event.publication_datetime) == '2016-10-15 22:00:00+00:00'
763
    assert str(event.publication_datetime.tzinfo) == 'UTC'
764
    assert event.duration == 90
765
    Event.objects.all().delete()
766
    resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
767
    resp.form['events_csv_file'] = Upload(
768
        't.csv',
769
        b'2016-09-16,18:00,10,5,label,slug,"description\nfoobar",pricing,url,2016-10-16 10:00,90',
770
        'text/csv',
771
    )
772
    resp = resp.form.submit(status=302)
773
    assert Event.objects.count() == 1
774
    event = Event.objects.get()
775
    assert event.description == 'description\nfoobar'
776
    assert event.pricing == 'pricing'
777
    assert event.url == 'url'
778
    assert str(event.publication_datetime) == '2016-10-16 08:00:00+00:00'
779
    assert str(event.publication_datetime.tzinfo) == 'UTC'
757 780
    assert event.duration == 90
758 781

  
759
    # publication date bad format
782
    # publication date/time bad format
760 783
    resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
761 784
    resp.form['events_csv_file'] = Upload(
762 785
        't.csv', b'2016-09-16,18:00,10,5,label,slug,description,pricing,url,foobar', 'text/csv'
763 786
    )
764 787
    resp = resp.form.submit(status=200)
765
    assert 'Invalid file format. (date format' in resp.text
788
    assert 'Invalid file format. (date/time format' in resp.text
766 789

  
767 790
    # duration bad format
768 791
    resp = app.get('/manage/agendas/%s/import-events' % agenda.id, status=200)
tests/test_agendas.py
446 446
    [
447 447
        # no delay
448 448
        (10, 0, 0, 0, None, True),
449
        # test publication_date
449
        # test publication_datetime
450 450
        (10, 0, 0, 0, 1, False),
451 451
        (10, 0, 0, 0, 0, True),
452 452
        # test min and max delays
......
464 464
    )
465 465
    event = Event.objects.create(
466 466
        start_datetime=localtime() + datetime.timedelta(days=start_days, minutes=start_minutes),
467
        publication_date=(localtime().date() + datetime.timedelta(days=pub_days)) if pub_days else None,
467
        publication_datetime=(localtime() + datetime.timedelta(days=pub_days)) if pub_days else None,
468 468
        places=10,
469 469
        agenda=agenda,
470 470
    )
tests/test_import_export.py
183 183
        description='description',
184 184
        pricing='100',
185 185
        url='https://example.net/',
186
        publication_date=datetime.date(2020, 5, 11),
186
        publication_datetime=make_aware(datetime.datetime(2020, 5, 11)),
187 187
        places=42,
188 188
        start_datetime=now(),
189 189
        duration=30,
......
214 214
    assert first_imported_event.description == 'description'
215 215
    assert first_imported_event.pricing == '100'
216 216
    assert first_imported_event.url == 'https://example.net/'
217
    assert first_imported_event.publication_date == datetime.date(2020, 5, 11)
217
    assert str(first_imported_event.publication_datetime) == '2020-05-10 22:00:00+00:00'
218
    assert str(first_imported_event.publication_datetime.tzinfo) == 'UTC'
218 219
    assert first_imported_event.duration == 30
219 220
    assert Agenda.objects.get(label='Foo Bar 2').event_set.first().slug == 'event'
220 221

  
221
-