From e134f6dfac4a6e105aa80d3af3308487f964e0ec Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Wed, 13 Jan 2021 15:08:40 +0100 Subject: [PATCH 1/2] agendas: add event recurrence end date (#51218) --- .../0076_event_recurrence_end_date.py | 20 +++++++++++++++++++ chrono/agendas/models.py | 9 +++++++++ chrono/manager/forms.py | 2 ++ tests/test_agendas.py | 20 +++++++++++++++++++ 4 files changed, 51 insertions(+) create mode 100644 chrono/agendas/migrations/0076_event_recurrence_end_date.py diff --git a/chrono/agendas/migrations/0076_event_recurrence_end_date.py b/chrono/agendas/migrations/0076_event_recurrence_end_date.py new file mode 100644 index 0000000..3ff05bf --- /dev/null +++ b/chrono/agendas/migrations/0076_event_recurrence_end_date.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.18 on 2021-02-16 15:10 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('agendas', '0075_auto_20210216_1553'), + ] + + operations = [ + migrations.AddField( + model_name='event', + name='recurrence_end_date', + field=models.DateField(blank=True, null=True, verbose_name='Recurrence end date'), + ), + ] diff --git a/chrono/agendas/models.py b/chrono/agendas/models.py index 18df797..2fd3f3c 100644 --- a/chrono/agendas/models.py +++ b/chrono/agendas/models.py @@ -1025,6 +1025,7 @@ class Event(models.Model): start_datetime = models.DateTimeField(_('Date/time')) repeat = models.CharField(_('Repeat'), max_length=16, blank=True, choices=REPEAT_CHOICES) recurrence_rule = JSONField(_('Recurrence rule'), null=True) + recurrence_end_date = models.DateField(_('Recurrence end date'), null=True, blank=True) primary_event = models.ForeignKey('self', null=True, on_delete=models.CASCADE, related_name='recurrences') duration = models.PositiveIntegerField(_('Duration (in minutes)'), default=None, null=True, blank=True) publication_date = models.DateField(_('Publication date'), blank=True, null=True) @@ -1201,11 +1202,15 @@ class Event(models.Model): event.save() def export_json(self): + recurrence_end_date = ( + self.recurrence_end_date.strftime('%Y-%m-%d') if self.recurrence_end_date else None + ) return { 'start_datetime': make_naive(self.start_datetime).strftime('%Y-%m-%d %H:%M:%S'), 'publication_date': self.publication_date.strftime('%Y-%m-%d') if self.publication_date else None, 'repeat': self.repeat, 'recurrence_rule': self.recurrence_rule, + 'recurrence_end_date': recurrence_end_date, 'places': self.places, 'waiting_list_places': self.waiting_list_places, 'label': self.label, @@ -1279,6 +1284,10 @@ class Event(models.Model): if self.publication_date and self.publication_date > min_datetime.date(): min_datetime = make_aware(datetime.datetime.combine(self.publication_date, datetime.time(0, 0))) + if self.recurrence_end_date: + self.recurrence_rule['until'] = datetime.datetime.combine( + self.recurrence_end_date, datetime.time(0, 0) + ) # remove pytz info because dateutil doesn't support DST changes min_datetime = make_naive(min_datetime) diff --git a/chrono/manager/forms.py b/chrono/manager/forms.py index 76b80c4..042ac44 100644 --- a/chrono/manager/forms.py +++ b/chrono/manager/forms.py @@ -184,12 +184,14 @@ class EventForm(forms.ModelForm): model = Event widgets = { 'publication_date': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'), + 'recurrence_end_date': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'), } fields = [ 'label', 'slug', 'start_datetime', 'repeat', + 'recurrence_end_date', 'duration', 'publication_date', 'places', diff --git a/tests/test_agendas.py b/tests/test_agendas.py index 575a1c3..0fd27c0 100644 --- a/tests/test_agendas.py +++ b/tests/test_agendas.py @@ -1957,3 +1957,23 @@ def test_recurring_events_repeat(freezer): assert ( recurrences[i].start_datetime + datetime.timedelta(days=14) == recurrences[i + 1].start_datetime ) + + +def test_recurring_events_with_end_date(): + agenda = Agenda.objects.create(label='Agenda', kind='events') + event = Event.objects.create( + agenda=agenda, + start_datetime=now(), + repeat='daily', + places=5, + recurrence_end_date=(now() + datetime.timedelta(days=5)).date(), + ) + event.refresh_from_db() + start_datetime = localtime(event.start_datetime) + + recurrences = event.get_recurrences( + localtime(event.start_datetime), localtime(event.start_datetime) + datetime.timedelta(days=10) + ) + assert len(recurrences) == 5 + assert recurrences[0].start_datetime == start_datetime + assert recurrences[-1].start_datetime == start_datetime + datetime.timedelta(days=4) -- 2.20.1