diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a7b08008..c8dfd6ec 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -14,6 +14,14 @@ Change Log Unreleased ---------- +[1.9.0] - 2024-06-14 +-------------------- + +Added +~~~~~~~ + +* RenderXBlockStarted filter added which allows reading / modifying of XBlock context prior to render. + [1.8.1] - 2024-04-12 -------------------- diff --git a/openedx_filters/__init__.py b/openedx_filters/__init__.py index b98bfe95..835c5d54 100644 --- a/openedx_filters/__init__.py +++ b/openedx_filters/__init__.py @@ -3,4 +3,4 @@ """ from openedx_filters.filters import * -__version__ = "1.8.1" +__version__ = "1.9.0" diff --git a/openedx_filters/learning/filters.py b/openedx_filters/learning/filters.py index ce28e2fe..f95e4f82 100644 --- a/openedx_filters/learning/filters.py +++ b/openedx_filters/learning/filters.py @@ -546,6 +546,46 @@ def run_filter(cls, enrollments): return data.get("enrollments") +class RenderXBlockStarted(OpenEdxPublicFilter): + """ + Filter in between context generation and rendering of XBlock scope. + """ + + filter_type = "org.openedx.learning.xblock.render.started.v1" + + class PreventXBlockBlockRender(OpenEdxFilterException): + """ + Custom class used to prevent the XBlock from rendering for the user. + """ + + class RenderCustomResponse(OpenEdxFilterException): + """ + Custom class used to stop the XBlock rendering process and return a custom response. + """ + + def __init__(self, message, response=None): + """ + Override init that defines specific arguments used in the XBlock render process. + + Arguments: + message: error message for the exception. + response: custom response which will be returned by the XBlock render view. + """ + super().__init__(message, response=response) + + @classmethod + def run_filter(cls, context, student_view_context): + """ + Execute a filter with the specified signature. + + Arguments: + context (dict): rendering context values like is_mobile_app, show_title, etc. + student_view_context (dict): context passed to the student_view of the block context + """ + data = super().run_pipeline(context=context, student_view_context=student_view_context) + return data.get("context"), data.get("student_view_context") + + class VerticalBlockRenderCompleted(OpenEdxPublicFilter): """ Custom class used to create filters to act on vertical block rendering completed. diff --git a/openedx_filters/learning/tests/test_filters.py b/openedx_filters/learning/tests/test_filters.py index f872d5dc..9021906b 100644 --- a/openedx_filters/learning/tests/test_filters.py +++ b/openedx_filters/learning/tests/test_filters.py @@ -22,6 +22,7 @@ DashboardRenderStarted, InstructorDashboardRenderStarted, ORASubmissionViewRenderStarted, + RenderXBlockStarted, StudentLoginRequested, StudentRegistrationRequested, VerticalBlockChildRenderStarted, @@ -479,6 +480,68 @@ def test_halt_vertical_block_render(self, render_exception, attributes): self.assertDictContainsSubset(attributes, exception.__dict__) + def test_xblock_render_started(self): + """ + Test RenderXBlockStarted filter behavior under normal conditions. + + Expected behavior: + - The filter must have the signature specified. + - The filter should return the expected values + """ + context = { + "foo": False, + "bar": "baz", + "buzz": 1337, + } + student_view_context = { + "arbitrary_context": "value", + "more_arbitrary_context": True + } + + result = VerticalBlockChildRenderStarted.run_filter(context, student_view_context) + + self.assertTupleEqual((context, student_view_context), result) + + @data( + ( + RenderXBlockStarted.PreventXBlockBlockRender, + { + "message": "Danger, Will Robinson!" + } + ) + ) + @unpack + def test_halt_xblock_render(self, xblock_render_exception, attributes): + """ + Test for xblock render exception attributes. + + Expected behavior: + - The exception must have the attributes specified. + """ + exception = xblock_render_exception(**attributes) + + self.assertDictContainsSubset(attributes, exception.__dict__) + + @data( + ( + RenderXBlockStarted.RenderCustomResponse, + { + "message": "Danger, Will Robinson!" + } + ) + ) + @unpack + def test_halt_xblock_render_custom_response(self, xblock_render_exception, attributes): + """ + Test for xblock render exception attributes. + + Expected behavior: + - The exception must have the attributes specified. + """ + exception = xblock_render_exception(**attributes) + + self.assertDictContainsSubset(attributes, exception.__dict__) + def test_account_settings_render_started(self): """ Test AccountSettingsRenderStarted filter behavior under normal conditions.