3939
4040import logging
4141import re
42+ import crum
4243
4344from openedx_filters .filters import PipelineStep
4445
46+ from .models import CourseArchiveStatus
47+
4548logger = logging .getLogger (__name__ )
4649
4750
48- class ChangeCourseAboutPageUrl (PipelineStep ):
51+ class AddArchiveStatusToLearnerHomeCourseRun (PipelineStep ):
4952 """
50- Filter to customize course about page URLs.
51-
52- This filter demonstrates how to intercept and modify course about page URLs,
53- redirecting them to external sites or custom implementations.
54-
55- Filter Hook Point:
56- This filter hooks into the course about page URL rendering process.
57- Register it for the filter: org.openedx.learning.course.about.render.started.v1
58-
59- Registration Example (in settings/common.py)::
60-
61- def plugin_settings(settings):
62- settings.OPEN_EDX_FILTERS_CONFIG = {
63- "org.openedx.learning.course.about.render.started.v1": {
64- "pipeline": [
65- "openedx_plugin_sample.pipeline.ChangeCourseAboutPageUrl"
66- ],
67- "fail_silently": False,
68- }
69- }
70-
71- Filter Documentation:
72- - Available Filters: https://docs.openedx.org/projects/openedx-filters/en/latest/reference/filters.html
73- - PipelineStep: https://docs.openedx.org/projects/openedx-filters/en/latest/reference/filters-tooling.html#openedx_filters.filters.PipelineStep
74-
75- Real-World Use Cases:
76- - Redirect to marketing site course pages
77- - Implement custom course discovery interfaces
78- - Add tracking parameters to URLs
79- - Route different course types to different platforms
80- - Implement A/B testing for course pages
53+ Customize each courseRun within a Learner Dashboard's /init API response to include the CourseArchiveStatus.
8154 """ # noqa: E501
8255
83- def run_filter (self , url , org , ** kwargs ): # pylint: disable=arguments-differ
56+ def run_filter (self , serialized_courserun , ** kwargs ): # pylint: disable=arguments-differ
8457 """
85- Modify the course about page URL.
86-
87- This method intercepts course about page URL generation and can modify
88- the destination URL based on business logic.
89-
90- Args:
91- url (str): The original course about page URL
92- org (str): The organization/institution identifier
93- **kwargs: Additional context data from the platform
94-
95- Returns:
96- dict: Dictionary with same parameter names as input
97- - url (str): Modified or original URL
98- - org (str): Organization identifier (usually unchanged)
99-
100- Raises:
101- FilterException: If processing should be halted
58+ Return a modified `serialized_courserun`, the data for one courseRun sent to the Learner Dashboard.
10259
103- Filter Requirements:
104- - Must return dictionary with keys matching input parameters
105- - Return None to skip this filter (let other filters run)
106- - Raise FilterException to halt pipeline execution
107- - Handle all input scenarios gracefully
108-
109- URL Pattern Matching:
110- This implementation looks for Open edX course keys in the format:
111- course-v1:ORG+COURSE+RUN (e.g., course-v1:edX+DemoX+Demo_Course)
112-
113- Documentation:
114- - run_filter method: https://docs.openedx.org/projects/openedx-filters/en/latest/reference/filters-tooling.html#openedx_filters.filters.PipelineStep.run_filter
60+ Inserts the `isArchivedByLearner` field (disambiguated from `isArchived`, which refers to whether the course run has
61+ been archived by the authors).
11562 """ # noqa: E501
116- # Extract course ID using Open edX course key pattern
117- # Course keys follow the format: course-v1:ORG+COURSE+RUN
118- pattern = r'(?P<course_id>course-v1:[^/]+)'
119-
120- match = re .search (pattern , url )
121- if match :
122- course_id = match .group ('course_id' )
123-
124- # Example: Redirect to external marketing site
125- new_url = f"https://example.com/new_about_page/{ course_id } "
126-
127- logger .debug (
128- f"Redirecting course about page for { course_id } from { url } to { new_url } "
129- )
130-
131- # Return modified data
132- return {"url" : new_url , "org" : org }
133-
134- # No course ID found - return original data unchanged
135- logger .debug (f"No course ID found in URL { url } , leaving unchanged" )
136- return {"url" : url , "org" : org }
137-
138- # Alternative patterns for different business logic:
139-
140- # Organization-based routing:
141- # if org == "special_org":
142- # new_url = f"https://special-site.com/courses/{course_id}"
143- # return {"url": new_url, "org": org}
144-
145- # Course type-based routing:
146- # if "MicroMasters" in course_id:
147- # new_url = f"https://micromasters.example.com/{course_id}"
148- # return {"url": new_url, "org": org}
149-
150- # A/B testing implementation:
151- # import random
152- # if random.choice([True, False]):
153- # new_url = f"https://variant-a.example.com/{course_id}"
154- # else:
155- # new_url = f"https://variant-b.example.com/{course_id}"
156- # return {"url": new_url, "org": org}
63+ user = crum .get_current_request ().user
64+ try :
65+ is_archived_by_learner = CourseArchiveStatus .objects .get (
66+ user = user , course_id = serialized_courserun ["courseId" ]
67+ ).is_archived
68+ except CourseArchiveStatus .DoesNotExist :
69+ is_archived_by_learner = False
70+ return {
71+ "serialized_courserun" : {
72+ ** serialized_courserun ,
73+ "isArchivedByLearner" : is_archived_by_learner ,
74+ },
75+ }
0 commit comments