diff --git a/program/filters.py b/program/filters.py index 60bbce5de6a0d766cbbc3bf807ac39d35d551041..af8421a919ffd1607b6c29dff3c70cec61654275 100644 --- a/program/filters.py +++ b/program/filters.py @@ -57,6 +57,10 @@ class ShowOrderingFilter(filters.OrderingFilter): class ShowFilterSet(StaticFilterHelpTextMixin, filters.FilterSet): + ids = IntegerInFilter( + field_name="id", + help_text="Return only shows matching the specified id(s).", + ) order = ShowOrderingFilter( fields=["name", "slug", "id", "is_active", "is_owner", "updated_at", "updated_by"], help_text="Order shows by the given field(s).", @@ -131,6 +135,7 @@ class ShowFilterSet(StaticFilterHelpTextMixin, filters.FilterSet): class Meta: model = models.Show fields = [ + "ids", "order", "category_ids", "category_slug", @@ -150,6 +155,10 @@ class ShowFilterSet(StaticFilterHelpTextMixin, filters.FilterSet): class ScheduleFilterSet(filters.FilterSet): + ids = IntegerInFilter( + field_name="id", + help_text="Return only schedules matching the specified id(s).", + ) show_ids = IntegerInFilter( field_name="show", help_text="Return only schedules that belong to the specified show(s).", @@ -171,6 +180,10 @@ class ScheduleFilterSet(filters.FilterSet): class TimeSlotFilterSet(filters.FilterSet): + ids = IntegerInFilter( + field_name="id", + help_text="Return only timeslots matching the specified id(s).", + ) order = filters.OrderingFilter( fields=[field.name for field in models.TimeSlot._meta.get_fields()] ) @@ -237,6 +250,7 @@ class TimeSlotFilterSet(filters.FilterSet): class Meta: model = models.TimeSlot fields = [ + "ids", "order", "start", "end", diff --git a/program/services.py b/program/services.py index 23497ed65fdfa6b9834ef7cb91c291c0820af385..86b9f0cd0434010c75b9281df0290856963b261c 100644 --- a/program/services.py +++ b/program/services.py @@ -720,13 +720,23 @@ def generate_program_entries( ) def create_timeslot_entry(timeslot: TimeSlot): - return create_entry(timeslot.start, timeslot.end, timeslot.schedule.show, timeslot) + return create_entry( + # Ensure the program entry never starts before the requested start + # and never ends after the requested end. + max(timeslot.start, start), + min(timeslot.end, end), + timeslot.schedule.show, + timeslot, + ) if start is None: start = timezone.now() if end is None: end = start + timedelta(days=1) - queryset = queryset.filter(start__gte=start, start__lt=end) + # Find all timeslots that + # * have started before the specified start value but end after it + # * or end after the specified end value but start before it + queryset = queryset.filter(end__gt=start, start__lt=end).order_by("start") if not include_virtual: yield from (create_timeslot_entry(timeslot) for timeslot in queryset) @@ -744,5 +754,5 @@ def generate_program_entries( yield create_entry(entry_start, timeslot.start, fallback_show) yield create_timeslot_entry(timeslot) entry_start = timeslot.end - if entry_start != end: + if entry_start < end: yield create_entry(entry_start, end, fallback_show) diff --git a/program/tests/test_basic_program.py b/program/tests/test_basic_program.py index bfc08892027b9a050dbe4883e9d1f3e5f6fb4e88..5e6df8c029ee4b1fa398f529ff183442478bf75a 100644 --- a/program/tests/test_basic_program.py +++ b/program/tests/test_basic_program.py @@ -50,9 +50,10 @@ def test_basic(admin_api_client, api_client, daily_rrule, show): response = api_client.get(url()) assert response.status_code == 200 - assert len(response.json()) == 1 + assert len(response.json()) == 2 - assert_entry(response.json()[0], show) + for entry in response.json(): + assert_entry(entry, show) def test_basic_one_week(admin_api_client, api_client, daily_rrule, show): @@ -86,14 +87,14 @@ def test_basic_include_virtual( assert response.status_code == 200 assert len(response.json()) == 3 - virtual_entry1, entry, virtual_entry2 = response.json() + entry1, virtual_entry, entry2 = response.json() - assert_virtual_entry(virtual_entry1, fallback_show) - assert_entry(entry, show) - assert_virtual_entry(virtual_entry2, fallback_show) + assert_entry(entry1, show) + assert_virtual_entry(virtual_entry, fallback_show) + assert_entry(entry2, show) - assert virtual_entry1["end"] == entry["start"] - assert entry["end"] == virtual_entry2["start"] + assert entry1["end"] == virtual_entry["start"] + assert virtual_entry["end"] == entry2["start"] def test_basic_one_week_include_virtual( @@ -118,11 +119,11 @@ def test_basic_one_week_include_virtual( entries = response.json() - for virtual_entry in entries[0::2]: - assert_virtual_entry(virtual_entry, fallback_show) - - for entry in entries[1::2]: + for entry in entries[0::2]: assert_entry(entry, show) + for virtual_entry in entries[1::2]: + assert_virtual_entry(virtual_entry, fallback_show) + for entry1, entry2 in pairwise(entries): assert entry1["end"] == entry2["start"] diff --git a/program/tests/test_calendar_program.py b/program/tests/test_calendar_program.py index 417f840fb2f0346d5161c6efb2cbfb82f5317bae..58379cd0ab751bd7013cc1a3e85411fbd22d0092 100644 --- a/program/tests/test_calendar_program.py +++ b/program/tests/test_calendar_program.py @@ -21,7 +21,7 @@ def url(include_virtual=False, start=None, end=None): def assert_episodes(episodes, one_week=False) -> None: """asserts the episodes are valid.""" - assert len(episodes) == 1 if not one_week else 7 + assert len(episodes) == 2 if not one_week else 7 for episode in episodes: assert episode["id"] @@ -31,20 +31,24 @@ def assert_episodes(episodes, one_week=False) -> None: def assert_program(program, show, fallback_show=None, one_week=False) -> None: """asserts the program are valid and correspond to the given show and fallback show.""" - assert len(program) == 1 if fallback_show is None and not one_week else (7 if one_week else 3) + assert len(program) == 2 if fallback_show is None and not one_week else (7 if one_week else 3) - assert program[0]["end"] - assert program[0]["id"] - assert program[0]["start"] + for entry in program: + assert entry["end"] + assert entry["id"] + assert entry["start"] if fallback_show is None: - assert program[0]["showId"] == show.id - assert program[0]["timeslotId"] + for entry in program: + assert entry["showId"] == show.id + assert entry["timeslotId"] else: - assert program[0]["showId"] == fallback_show.id - - assert program[1]["showId"] == show.id - assert program[1]["timeslotId"] + for entry in program: + if entry["timeslotId"]: + assert entry["showId"] == show.id + assert entry["timeslotId"] + else: + assert entry["showId"] == fallback_show.id def assert_shows(shows, show, fallback_show=None) -> None: @@ -66,7 +70,7 @@ def assert_shows(shows, show, fallback_show=None) -> None: def assert_timeslots(timeslots, show, one_week=False) -> None: """asserts the timeslots are valid and correspond to the given show.""" - assert len(timeslots) == 1 if not one_week else 7 + assert len(timeslots) == 2 if not one_week else 7 for timeslot in timeslots: assert timeslot["id"] diff --git a/program/tests/test_playout.py b/program/tests/test_playout.py index acf2c217a01dbee02c8751c5e15a0f88ffe4b2de..dd6e29063c0441353c9ba3aea1c4365e8a5317a7 100644 --- a/program/tests/test_playout.py +++ b/program/tests/test_playout.py @@ -51,9 +51,10 @@ def test_playout(admin_api_client, api_client, daily_rrule, show): response = api_client.get(url()) assert response.status_code == 200 - assert len(response.json()) == 1 + assert len(response.json()) == 2 - assert_entry(response.json()[0], show) + for entry in response.json(): + assert_entry(entry, show) def test_playout_one_week(admin_api_client, api_client, daily_rrule, show): @@ -86,14 +87,14 @@ def test_playout_include_virtual( assert response.status_code == 200 assert len(response.json()) == 3 - virtual_entry1, entry, virtual_entry2 = response.json() + entry1, virtual_entry, entry2 = response.json() - assert_virtual_entry(virtual_entry1, fallback_show) - assert_entry(entry, show) - assert_virtual_entry(virtual_entry2, fallback_show) + assert_entry(entry1, show) + assert_virtual_entry(virtual_entry, fallback_show) + assert_entry(entry1, show) - assert virtual_entry1["end"] == entry["start"] - assert entry["end"] == virtual_entry2["start"] + assert entry1["end"] == virtual_entry["start"] + assert virtual_entry["end"] == entry2["start"] def test_playout_one_week_include_virtual( @@ -118,11 +119,11 @@ def test_playout_one_week_include_virtual( entries = response.json() - for virtual_entry in entries[0::2]: - assert_virtual_entry(virtual_entry, fallback_show) - - for entry in entries[1::2]: + for entry in entries[0::2]: assert_entry(entry, show) + for virtual_entry in entries[1::2]: + assert_virtual_entry(virtual_entry, fallback_show) + for entry1, entry2 in pairwise(entries): assert entry1["end"] == entry2["start"]