diff --git a/RELEASE.rst b/RELEASE.rst index b8e1dbd024..27c39f9f18 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -1,6 +1,11 @@ Release Notes ============= +Version 1.144.1 +--------------- + +- Filter non-live parent programs from v2/courses, v2/programs, similar to v1 (#3436) + Version 1.144.0 (Released March 30, 2026) --------------- diff --git a/courses/serializers/v2/courses.py b/courses/serializers/v2/courses.py index 1b8a1fa7b5..cc3220fb9a 100644 --- a/courses/serializers/v2/courses.py +++ b/courses/serializers/v2/courses.py @@ -137,6 +137,10 @@ def get_programs(self, instance): else: programs_qs = programs_qs.filter(program__b2b_only=False) + programs_qs = programs_qs.filter( + program__live=True, program__page__live=True + ) + programs = [ req.program for req in programs_qs.prefetch_related("program").all() ] diff --git a/courses/serializers/v2/courses_test.py b/courses/serializers/v2/courses_test.py index bf8bc8b1d6..78fd3c629f 100644 --- a/courses/serializers/v2/courses_test.py +++ b/courses/serializers/v2/courses_test.py @@ -163,6 +163,37 @@ def test_serialize_course_required_prerequisites( ) +@pytest.mark.parametrize( + ("program_live", "page_live", "expected_in_programs"), + [ + (True, True, True), + (False, True, False), + (True, False, False), + (False, False, False), + ], +) +def test_serialize_course_programs_excludes_non_live( + mock_context, + program_live, + page_live, + expected_in_programs, +): + """Test that get_programs excludes programs where live=False or page.live=False""" + mock_context["include_programs"] = True + course = CourseFactory.create() + program = ProgramFactory.create(live=program_live) + program.page.live = page_live + program.page.save() + program.add_requirement(course) + + data = CourseWithCourseRunsSerializer(instance=course, context=mock_context).data + + if expected_in_programs: + assert len(data["programs"]) == 1 + else: + assert data["programs"] == [] + + class TestCourseRunEnrollmentSerializerV2: """Test the v2 CourseRunEnrollmentSerializer.""" diff --git a/courses/serializers/v2/programs.py b/courses/serializers/v2/programs.py index 78d503889b..1c06fa6afa 100644 --- a/courses/serializers/v2/programs.py +++ b/courses/serializers/v2/programs.py @@ -184,6 +184,8 @@ def get_programs(self, instance): else: programs_qs = programs_qs.filter(program__b2b_only=False) + programs_qs = programs_qs.filter(program__live=True, program__page__live=True) + programs = [req.program for req in programs_qs.select_related("program").all()] return BaseProgramSerializer(programs, many=True).data diff --git a/courses/serializers/v2/programs_test.py b/courses/serializers/v2/programs_test.py index 2d292bf63a..a4f739df20 100644 --- a/courses/serializers/v2/programs_test.py +++ b/courses/serializers/v2/programs_test.py @@ -161,6 +161,39 @@ def test_serialize_program( ) +@pytest.mark.parametrize( + ("parent_program_live", "parent_page_live", "expected_in_programs"), + [ + (True, True, True), + (False, True, False), + (True, False, False), + (False, False, False), + ], +) +def test_serialize_program_programs_excludes_non_live( + mock_context, + program_with_empty_requirements, # noqa: F811 + parent_program_live, + parent_page_live, + expected_in_programs, +): + """Test that get_programs excludes parent programs where live=False or page.live=False""" + mock_context["include_programs"] = True + parent_program = ProgramFactory.create(live=parent_program_live) + parent_program.page.live = parent_page_live + parent_program.page.save() + parent_program.add_requirement(program_with_empty_requirements) + + data = ProgramSerializer( + instance=program_with_empty_requirements, context=mock_context + ).data + + if expected_in_programs: + assert len(data["programs"]) == 1 + else: + assert data["programs"] == [] + + @pytest.mark.parametrize( ("has_paid_mode", "expected"), [ diff --git a/main/settings.py b/main/settings.py index 2b1e58b2a9..b95a4a54b9 100644 --- a/main/settings.py +++ b/main/settings.py @@ -37,7 +37,7 @@ from main.sentry import init_sentry from openapi.settings_spectacular import open_spectacular_settings -VERSION = "1.144.0" +VERSION = "1.144.1" log = logging.getLogger()