From 686782344005a6535d73f71e737c24be055dc804 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 16 Mar 2026 22:02:27 +0000 Subject: [PATCH 1/4] Update dependency authlib to v1.6.9 [SECURITY] (#3388) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- uv.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/uv.lock b/uv.lock index 6619e45dd0..757d779e71 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,6 @@ version = 1 -revision = 2 -requires-python = ">=3.11.0, <3.12" +revision = 3 +requires-python = "==3.11.*" [[package]] name = "amqp" @@ -79,14 +79,14 @@ wheels = [ [[package]] name = "authlib" -version = "1.6.8" +version = "1.6.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6b/6c/c88eac87468c607f88bc24df1f3b31445ee6fc9ba123b09e666adf687cd9/authlib-1.6.8.tar.gz", hash = "sha256:41ae180a17cf672bc784e4a518e5c82687f1fe1e98b0cafaeda80c8e4ab2d1cb", size = 165074, upload-time = "2026-02-14T04:02:17.941Z" } +sdist = { url = "https://files.pythonhosted.org/packages/af/98/00d3dd826d46959ad8e32af2dbb2398868fd9fd0683c26e56d0789bd0e68/authlib-1.6.9.tar.gz", hash = "sha256:d8f2421e7e5980cc1ddb4e32d3f5fa659cfaf60d8eaf3281ebed192e4ab74f04", size = 165134, upload-time = "2026-03-02T07:44:01.998Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/73/f7084bf12755113cd535ae586782ff3a6e710bfbe6a0d13d1c2f81ffbbfa/authlib-1.6.8-py2.py3-none-any.whl", hash = "sha256:97286fd7a15e6cfefc32771c8ef9c54f0ed58028f1322de6a2a7c969c3817888", size = 244116, upload-time = "2026-02-14T04:02:15.579Z" }, + { url = "https://files.pythonhosted.org/packages/53/23/b65f568ed0c22f1efacb744d2db1a33c8068f384b8c9b482b52ebdbc3ef6/authlib-1.6.9-py2.py3-none-any.whl", hash = "sha256:f08b4c14e08f0861dc18a32357b33fbcfd2ea86cfe3fe149484b4d764c4a0ac3", size = 244197, upload-time = "2026-03-02T07:44:00.307Z" }, ] [[package]] From 3caa514eda14a30e3f6fd71204e474f89f2d7e61 Mon Sep 17 00:00:00 2001 From: cp-at-mit Date: Tue, 17 Mar 2026 11:57:13 -0400 Subject: [PATCH 2/4] Add live filter to finance assistance forms (#3384) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- cms/serializers.py | 8 +++++--- cms/serializers_test.py | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/cms/serializers.py b/cms/serializers.py index 21acf44ecb..ecf2da3778 100644 --- a/cms/serializers.py +++ b/cms/serializers.py @@ -79,9 +79,11 @@ def _get_financial_assistance_url(self, page, slug): def _get_course_specific_form(self, instance): """Get financial assistance form specific to the course.""" - return FlexiblePricingRequestForm.objects.filter( - selected_course=instance.product - ).first() + return ( + FlexiblePricingRequestForm.objects.filter(selected_course=instance.product) + .live() + .first() + ) def _get_child_form(self, instance): """Get financial assistance form from child pages.""" diff --git a/cms/serializers_test.py b/cms/serializers_test.py index d2ad422d29..520e8a07b4 100644 --- a/cms/serializers_test.py +++ b/cms/serializers_test.py @@ -355,6 +355,31 @@ def test_serialized_course_finaid_form_url_publishing_states( assert serialized_output["financial_assistance_form_url"] == "" +def test_get_course_specific_form_returns_only_live_forms(fully_configured_wagtail): + """_get_course_specific_form should ignore non-live forms and return the live one.""" + + course_page = CoursePageFactory() + + # Non-live form for this course + FlexiblePricingFormFactory( + parent=course_page, + selected_course=course_page.product, + live=False, + ) + + # Live form for this course + live_form = FlexiblePricingFormFactory( + parent=course_page, + selected_course=course_page.product, + live=True, + ) + + serializer = CoursePageSerializer() + result = serializer._get_course_specific_form(course_page) # noqa: SLF001 + + assert result == live_form + + def test_serialize_program_page( mocker, fully_configured_wagtail, staff_user, mock_context ): From 8aa8bed65c62f5ce3b7a6dbf22801b5c055b33cb Mon Sep 17 00:00:00 2001 From: cp-at-mit Date: Tue, 17 Mar 2026 11:57:21 -0400 Subject: [PATCH 3/4] Prefer parent page for financial form URL (#3387) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- cms/serializers.py | 12 ++++++++++ cms/serializers_test.py | 50 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/cms/serializers.py b/cms/serializers.py index ecf2da3778..6b4ca8331c 100644 --- a/cms/serializers.py +++ b/cms/serializers.py @@ -310,6 +310,18 @@ def get_financial_assistance_form_url(self, instance): .first() ) + # If a form is found via selected_program, prefer its parent page + # (e.g., a course or program page) when constructing the URL. This + # ensures that forms which are children of course pages but linked to + # a program use the correct /courses/ URL instead of the program URL. + if financial_assistance_page is not None: + parent = financial_assistance_page.get_parent() + if parent is not None: + parent_page = getattr(parent, "specific", parent) + return self._get_financial_assistance_url( + parent_page, financial_assistance_page.slug + ) + # Check for child form if no direct link found if financial_assistance_page is None: page_children = instance.get_children() diff --git a/cms/serializers_test.py b/cms/serializers_test.py index 520e8a07b4..4974244cc9 100644 --- a/cms/serializers_test.py +++ b/cms/serializers_test.py @@ -415,6 +415,56 @@ def test_serialize_program_page( ) +def test_serialize_program_page__form_child_of_course_with_program_fk( + mocker, fully_configured_wagtail, staff_user, mock_context +): + """Program page uses course URL when form is child of course page. + + This covers the case where a financial assistance form is created under a + course page in Wagtail but is linked to a program via the Selected Program + FK. The program page should link to the course-based URL for the form + rather than a /programs/ URL. + """ + + fake_image_src = "http://example.com/my.img" + patched_get_wagtail_src = mocker.patch( # noqa: F841 + "cms.serializers.get_wagtail_img_src", return_value=fake_image_src + ) + + program = ProgramFactory(page=None) + program_page = ProgramPageFactory(program=program) + + course = CourseFactory(page=None) + program.add_requirement(course) + course_page = CoursePageFactory(course=course) + + financial_assistance_form = FlexiblePricingFormFactory( + selected_program_id=program.id, parent=course_page + ) + + rf = RequestFactory() + request = rf.get("/") + request.user = staff_user + + data = ProgramPageSerializer( + instance=program_page, context=program_page.get_context(request) + ).data + + assert_drf_json_equal( + data, + { + "feature_image_src": fake_image_src, + "page_url": program_page.url, + "financial_assistance_form_url": f"{course_page.get_url()}{financial_assistance_form.slug}/", + "description": bleach.clean(program_page.description, tags={}, strip=True), + "live": True, + "length": program_page.length, + "effort": program_page.effort, + "price": None, + }, + ) + + def test_serialize_program_page__with_related_financial_form( mocker, fully_configured_wagtail, staff_user, mock_context ): From 3d417fe4165570cc1c9b12c391ea67a7672d2249 Mon Sep 17 00:00:00 2001 From: Doof Date: Tue, 17 Mar 2026 16:16:59 +0000 Subject: [PATCH 4/4] Release 1.142.1 --- RELEASE.rst | 7 +++++++ main/settings.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/RELEASE.rst b/RELEASE.rst index e06e77fa69..6084e36bb1 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -1,6 +1,13 @@ Release Notes ============= +Version 1.142.1 +--------------- + +- Prefer parent page for financial form URL (#3387) +- Add live filter to finance assistance forms (#3384) +- Update dependency authlib to v1.6.9 [SECURITY] (#3388) + Version 1.142.0 (Released March 17, 2026) --------------- diff --git a/main/settings.py b/main/settings.py index f892ca143b..9405701e8e 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.142.0" +VERSION = "1.142.1" log = logging.getLogger()