From 2203e80e328ff65ff878b209bea08355d1617d3c Mon Sep 17 00:00:00 2001 From: Ernesto Rico Schmidt <ernesto@helsinki.at> Date: Tue, 8 Mar 2022 13:22:24 -0400 Subject: [PATCH] Rename byweekday, dtstart, tstart, tend and until in Schedule - update the model - migrate the model - update the serializer - update the views --- program/migrations/0017_auto_20220302_1711.py | 42 ++++++ program/models.py | 138 +++++++++--------- program/serializers.py | 16 +- program/views.py | 8 +- 4 files changed, 128 insertions(+), 76 deletions(-) create mode 100644 program/migrations/0017_auto_20220302_1711.py diff --git a/program/migrations/0017_auto_20220302_1711.py b/program/migrations/0017_auto_20220302_1711.py new file mode 100644 index 00000000..3d49ba5f --- /dev/null +++ b/program/migrations/0017_auto_20220302_1711.py @@ -0,0 +1,42 @@ +# Generated by Django 3.2.11 on 2022-03-02 16:11 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('program', '0016_auto_20220222_0209'), + ] + + operations = [ + migrations.AlterModelOptions( + name='schedule', + options={'ordering': ('first_date', 'start_time')}, + ), + migrations.RenameField( + model_name='schedule', + old_name='byweekday', + new_name='by_weekday', + ), + migrations.RenameField( + model_name='schedule', + old_name='tend', + new_name='end_time', + ), + migrations.RenameField( + model_name='schedule', + old_name='dstart', + new_name='first_date', + ), + migrations.RenameField( + model_name='schedule', + old_name='until', + new_name='last_date', + ), + migrations.RenameField( + model_name='schedule', + old_name='tstart', + new_name='start_time', + ), + ] diff --git a/program/models.py b/program/models.py index 8fdc7ee3..f0f0df2b 100644 --- a/program/models.py +++ b/program/models.py @@ -193,19 +193,19 @@ class RRule(models.Model): class Schedule(models.Model): rrule = models.ForeignKey(RRule, on_delete=models.CASCADE, related_name='schedules') - byweekday = models.IntegerField() show = models.ForeignKey(Show, on_delete=models.CASCADE, related_name='schedules') - dstart = models.DateField() - tstart = models.TimeField() - tend = models.TimeField() - until = models.DateField() + by_weekday = models.IntegerField() + first_date = models.DateField() + start_time = models.TimeField() + end_time = models.TimeField() + last_date = models.DateField() is_repetition = models.BooleanField(default=False) add_days_no = models.IntegerField(blank=True, null=True) add_business_days_only = models.BooleanField(default=False) default_playlist_id = models.IntegerField(blank=True, null=True) class Meta: - ordering = ('dstart', 'tstart') + ordering = ('first_date', 'start_time') # FIXME: this does not belong here @staticmethod @@ -220,29 +220,33 @@ class Schedule(models.Model): add_days_no = int(sdl['add_days_no']) if sdl.get('add_days_no') else None add_business_days_only = True if sdl.get('add_business_days_only') is True else False - dstart = parse_date(str(sdl['dstart'])) + # TODO: replace `dstart` with `first_date` when the dashboard is updated + first_date = parse_date(str(sdl['dstart'])) + # TODO: replace `tstart` with `start_time` when the dashboard is updated + start_time = sdl['tstart'] + ':00' if len(str(sdl['tstart'])) == 5 else sdl['tstart'] + # TODO: replace `tend` with `end_time` when the dashboard is updated + end_time = sdl['tend'] + ':00' if len(str(sdl['tend'])) == 5 else sdl['tend'] - tstart = sdl['tstart'] + ':00' if len(str(sdl['tstart'])) == 5 else sdl['tstart'] - tend = sdl['tend'] + ':00' if len(str(sdl['tend'])) == 5 else sdl['tend'] - - tstart = parse_time(str(tstart)) - tend = parse_time(str(tend)) + start_time = parse_time(str(start_time)) + end_time = parse_time(str(end_time)) + # TODO: replace `until` with `last_date` when the dashboard is updated if sdl['until']: - until = parse_date(str(sdl['until'])) + last_date = parse_date(str(sdl['until'])) else: # If no until date was set # Set it to the end of the year # Or add x days if AUTO_SET_UNTIL_DATE_TO_END_OF_YEAR: year = timezone.now().year - until = parse_date(f'{year}-12-31') + last_date = parse_date(f'{year}-12-31') else: - until = dstart + timedelta(days=+AUTO_SET_UNTIL_DATE_TO_DAYS_IN_FUTURE) + last_date = first_date + timedelta(days=+AUTO_SET_UNTIL_DATE_TO_DAYS_IN_FUTURE) - schedule = Schedule(pk=pk, byweekday=sdl['byweekday'], rrule=rrule, - dstart=dstart, tstart=tstart, tend=tend, - until=until, is_repetition=is_repetition, + # TODO: replace `byweekday` with `by_weekday` when the dashboard is updated + schedule = Schedule(pk=pk, by_weekday=sdl['byweekday'], rrule=rrule, + first_date=first_date, start_time=start_time, end_time=end_time, + last_date=last_date, is_repetition=is_repetition, default_playlist_id=default_playlist_id, show=show, add_days_no=add_days_no, add_business_days_only=add_business_days_only) @@ -256,76 +260,76 @@ class Schedule(models.Model): Returns past timeslots as well, starting from dstart (not today) """ - byweekno = None - byweekno_end = None - byweekday_end = int(schedule.byweekday) + by_week_no = None + by_week_no_end = None + by_weekday_end = int(schedule.by_weekday) starts = [] ends = [] timeslots = [] # Handle ending weekday for timeslots over midnight - if schedule.tend < schedule.tstart: - if schedule.byweekday < 6: - byweekday_end = int(schedule.byweekday + 1) + if schedule.end_time < schedule.start_time: + if schedule.by_weekday < 6: + by_weekday_end = int(schedule.by_weekday + 1) else: - byweekday_end = 0 + by_weekday_end = 0 # Handle ending dates for timeslots over midnight - if schedule.tend < schedule.tstart: - dend = schedule.dstart + timedelta(days=+1) + if schedule.end_time < schedule.start_time: + last_date = schedule.first_date + timedelta(days=+1) else: - dend = schedule.dstart + last_date = schedule.first_date if schedule.rrule.freq == 0: # Ignore weekdays for one-time timeslots - byweekday_start = None - byweekday_end = None + by_weekday_start = None + by_weekday_end = None elif schedule.rrule.freq == 3 and schedule.rrule.pk == 2: # Daily timeslots - byweekday_start = (0, 1, 2, 3, 4, 5, 6) - byweekday_end = (0, 1, 2, 3, 4, 5, 6) + by_weekday_start = (0, 1, 2, 3, 4, 5, 6) + by_weekday_end = (0, 1, 2, 3, 4, 5, 6) elif schedule.rrule.freq == 3 and schedule.rrule.pk == 3: # Business days MO - FR/SA - byweekday_start = (0, 1, 2, 3, 4) - if schedule.tend < schedule.tstart: + by_weekday_start = (0, 1, 2, 3, 4) + if schedule.end_time < schedule.start_time: # End days for over midnight - byweekday_end = (1, 2, 3, 4, 5) + by_weekday_end = (1, 2, 3, 4, 5) else: - byweekday_end = (0, 1, 2, 3, 4) + by_weekday_end = (0, 1, 2, 3, 4) elif schedule.rrule.freq == 2 and schedule.rrule.pk == 7: # Even calendar weeks - byweekday_start = int(schedule.byweekday) - byweekno = list(range(2, 54, 2)) + by_weekday_start = int(schedule.by_weekday) + by_week_no = list(range(2, 54, 2)) # Reverse ending weeks if from Sun - Mon - if byweekday_start == 6 and byweekday_end == 0: - byweekno_end = list(range(1, 54, 2)) + if by_weekday_start == 6 and by_weekday_end == 0: + by_week_no_end = list(range(1, 54, 2)) else: - byweekno_end = byweekno + by_week_no_end = by_week_no elif schedule.rrule.freq == 2 and schedule.rrule.pk == 8: # Odd calendar weeks - byweekday_start = int(schedule.byweekday) - byweekno = list(range(1, 54, 2)) + by_weekday_start = int(schedule.by_weekday) + by_week_no = list(range(1, 54, 2)) # Reverse ending weeks if from Sun - Mon - if byweekday_start == 6 and byweekday_end == 0: - byweekno_end = list(range(2, 54, 2)) + if by_weekday_start == 6 and by_weekday_end == 0: + by_week_no_end = list(range(2, 54, 2)) else: - byweekno_end = byweekno + by_week_no_end = by_week_no else: - byweekday_start = int(schedule.byweekday) + by_weekday_start = int(schedule.by_weekday) if schedule.rrule.freq == 0: - starts.append(datetime.combine(schedule.dstart, schedule.tstart)) - ends.append(datetime.combine(dend, schedule.tend)) + starts.append(datetime.combine(schedule.first_date, schedule.start_time)) + ends.append(datetime.combine(last_date, schedule.end_time)) else: starts = list(rrule(freq=schedule.rrule.freq, - dtstart=datetime.combine(schedule.dstart, schedule.tstart), + dtstart=datetime.combine(schedule.first_date, schedule.start_time), interval=schedule.rrule.interval, - until=schedule.until + relativedelta(days=+1), + until=schedule.last_date + relativedelta(days=+1), bysetpos=schedule.rrule.by_set_pos, - byweekday=byweekday_start, - byweekno=byweekno)) + byweekday=by_weekday_start, + byweekno=by_week_no)) ends = list(rrule(freq=schedule.rrule.freq, - dtstart=datetime.combine(dend, schedule.tend), + dtstart=datetime.combine(last_date, schedule.end_time), interval=schedule.rrule.interval, - until=schedule.until + relativedelta(days=+1), + until=schedule.last_date + relativedelta(days=+1), bysetpos=schedule.rrule.by_set_pos, - byweekday=byweekday_end, - byweekno=byweekno_end)) + byweekday=by_weekday_end, + byweekno=by_week_no_end)) for k in range(min(len(starts), len(ends))): @@ -334,7 +338,7 @@ class Schedule(models.Model): # produces wrong end dates if the 1st Tuesday is before the 1st Monday # In this case we take the next day instead of rrule's calculated end if starts[k] > ends[k]: - ends[k] = datetime.combine(starts[k] + relativedelta(days=+1), schedule.tend) + ends[k] = datetime.combine(starts[k] + relativedelta(days=+1), schedule.end_time) ''' Add a number of days to the generated dates? @@ -370,8 +374,8 @@ class Schedule(models.Model): starts[k] = starts[k] + relativedelta(days=+schedule.add_days_no) ends[k] = ends[k] + relativedelta(days=+schedule.add_days_no) - if ends[k].date() > schedule.until: - schedule.until = ends[k].date() + if ends[k].date() > schedule.last_date: + schedule.last_date = ends[k].date() timeslots.append(TimeSlot(schedule=schedule, start=timezone.make_aware(starts[k]), end=timezone.make_aware(ends[k]))) return timeslots @@ -545,9 +549,9 @@ class Schedule(models.Model): if schedule_pk is not None: existing_schedule = Schedule.objects.get(pk=int(schedule_pk)) - if schedule.until > existing_schedule.until: + if schedule.last_date > existing_schedule.last_date: last_timeslot = TimeSlot.objects.filter(schedule=existing_schedule).order_by('start').reverse()[0] - gen_schedule.dstart = last_timeslot.start.date() + timedelta(days=1) + gen_schedule.first_date = last_timeslot.start.date() + timedelta(days=1) timeslots = Schedule.generate_timeslots(gen_schedule) @@ -576,10 +580,10 @@ class Schedule(models.Model): show = schedule.show conflicts = Schedule.make_conflicts(sdl, schedule_pk, show_pk) - if schedule.rrule.freq > 0 and schedule.dstart == schedule.until: + if schedule.rrule.freq > 0 and schedule.first_date == schedule.last_date: return {'detail': _("Start and until dates mustn't be the same")} - if schedule.until < schedule.dstart: + if schedule.last_date < schedule.first_date: return {'detail': _("Until date mustn't be before start")} num_conflicts = len([pr for pr in conflicts['projected'] if len(pr['collisions']) > 0]) @@ -764,7 +768,7 @@ class Schedule(models.Model): return conflicts # Collect upcoming timeslots to delete which might still remain - del_timeslots = TimeSlot.objects.filter(schedule=schedule, start__gt=schedule.until) + del_timeslots = TimeSlot.objects.filter(schedule=schedule, start__gt=schedule.last_date) for del_ts in del_timeslots: delete.append(del_ts) @@ -854,9 +858,9 @@ class TimeSlotManager(models.Manager): class TimeSlot(models.Model): schedule = models.ForeignKey(Schedule, on_delete=models.CASCADE, related_name='timeslots') + show = models.ForeignKey(Show, editable=False, on_delete=models.CASCADE, related_name='timeslots') start = models.DateTimeField() end = models.DateTimeField() - show = models.ForeignKey(Show, editable=False, on_delete=models.CASCADE, related_name='timeslots') memo = models.TextField(blank=True) is_repetition = models.BooleanField(default=False) playlist_id = models.IntegerField(null=True) @@ -874,7 +878,7 @@ class TimeSlot(models.Model): @property def hash(self): - string = str(self.start) + str(self.end) + str(self.schedule.rrule.id) + str(self.schedule.byweekday) + string = str(self.start) + str(self.end) + str(self.schedule.rrule.id) + str(self.schedule.by_weekday) return str(''.join(s for s in string if s.isdigit())) diff --git a/program/serializers.py b/program/serializers.py index 70576fbc..911cc00d 100644 --- a/program/serializers.py +++ b/program/serializers.py @@ -298,6 +298,12 @@ class ShowSerializer(serializers.HyperlinkedModelSerializer): class ScheduleSerializer(serializers.ModelSerializer): rrule = serializers.PrimaryKeyRelatedField(queryset=RRule.objects.all()) show = serializers.PrimaryKeyRelatedField(queryset=Show.objects.all()) + # TODO: remove this when the dashboard is updated + byweekday = serializers.IntegerField(source='by_weekday') + dstart = serializers.DateField(source='first_date') + tstart = serializers.TimeField(source='start_time') + tend = serializers.TimeField(source='end_time') + until = serializers.DateField(source='last_date') class Meta: model = Schedule @@ -319,11 +325,11 @@ class ScheduleSerializer(serializers.ModelSerializer): def update(self, instance, validated_data): """Update and return an existing Schedule instance, given the validated data.""" - instance.byweekday = validated_data.get('byweekday', instance.byweekday) - instance.dstart = validated_data.get('dstart', instance.dstart) - instance.tstart = validated_data.get('tstart', instance.tstart) - instance.tend = validated_data.get('tend', instance.tend) - instance.until = validated_data.get('until', instance.until) + instance.by_weekday = validated_data.get('byweekday', instance.by_weekday) + instance.first_date = validated_data.get('dstart', instance.first_date) + instance.start_time = validated_data.get('tstart', instance.start_time) + instance.end_time = validated_data.get('tend', instance.end_time) + instance.last_date = validated_data.get('until', instance.last_date) instance.is_repetition = validated_data.get('is_repetition', instance.is_repetition) instance.default_playlist_id = validated_data.get('default_playlist_id', instance.default_playlist_id) instance.rrule = validated_data.get('rrule', instance.rrule) diff --git a/program/views.py b/program/views.py index ae4ede3d..b6c6bb78 100644 --- a/program/views.py +++ b/program/views.py @@ -260,13 +260,13 @@ class APIShowViewSet(viewsets.ModelViewSet): # Filter currently running shows # Get currently running schedules to filter by first # For single dates we test if there'll be one in the future (and ignore the until date) - # TODO: Really consider dstart? (=currently active, not just upcoming ones) + # TODO: Really consider first_date? (=currently active, not just upcoming ones) # Add limit for future? show_ids = Schedule.objects.filter(Q(rrule_id__gt=1, - dstart__lte=timezone.now(), - until__gte=timezone.now()) | + first_date__lte=timezone.now(), + last_date__gte=timezone.now()) | Q(rrule_id=1, - dstart__gte=timezone.now()) + first_date__gte=timezone.now()) ).distinct().values_list('show_id', flat=True) # Filter active shows based on timeslots as well as on the is_active flag -- GitLab