We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
og:image is not set propertly
## Bug Report

**Expected behavior/code**
For SEO purpose, we add open graph tags into CMS pages. These tags should be properly configured.

**Actual Behavior**
On CMS Page, `og:image` url is malformed.

**Steps to Reproduce**
1. Go to a CMS Page
2. Use [facebook debug tool](https://developers.facebook.com/tools/debug/) to check link preview for the CMS Page
3.  Note that `og:image` tag is not valid

**Environment**
- Richie version: 2.8.2
- Platform: Mac OS 12.0.1 - Firefox 93.0

**Possible Solution**
- Fix the `og:image` attribute

**Additional context/Screenshots**
- https://developers.facebook.com/tools/debug/?q=https%3A%2F%2Fwww.fun-mooc.fr%2Ffr%2Fcours%2Fmooc-elles-font-lart%2F
- https://developers.facebook.com/tools/debug/?q=https%3A%2F%2Fwww.fun-mooc.fr%2Ffr%2Factualites%2Fdeveloppement-des-territoires-comment-agir-pour-construire-laven%2F


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/richie/apps/core/context_processors.py`
Content:
```
1 """
2 Template context processors
3 """
4 import json
5 from collections import OrderedDict
6 
7 from django.conf import settings
8 from django.contrib.sites.models import Site
9 from django.http.request import HttpRequest
10 from django.middleware.csrf import get_token
11 from django.utils.translation import get_language_from_request
12 
13 from richie.apps.courses.defaults import RICHIE_MAX_ARCHIVED_COURSE_RUNS
14 from richie.apps.courses.models import Organization
15 
16 from . import defaults
17 
18 
19 def site_metas(request: HttpRequest):
20     """
21     Context processor to add all information required by Richie CMS templates and frontend.
22 
23     If `CDN_DOMAIN` settings is defined we add it in the context. It allows
24     to load statics js on a CDN like cloudfront.
25     """
26     site_current = Site.objects.get_current()
27     protocol = "https" if request.is_secure() else "http"
28 
29     context = {
30         **{
31             f"GLIMPSE_PAGINATION_{k.upper()}": v
32             for k, v in {
33                 **defaults.GLIMPSE_PAGINATION,
34                 **getattr(settings, "RICHIE_GLIMPSE_PAGINATION", {}),
35             }.items()
36         },
37         "SITE": {
38             "name": site_current.name,
39             "domain": site_current.domain,
40             "web_url": f"{protocol:s}://{site_current.domain:s}",
41         },
42         "FRONTEND_CONTEXT": {
43             "context": {
44                 "csrftoken": get_token(request),
45                 "environment": getattr(settings, "ENVIRONMENT", ""),
46                 "release": getattr(settings, "RELEASE", ""),
47                 "sentry_dsn": getattr(settings, "SENTRY_DSN", ""),
48             }
49         },
50         **WebAnalyticsContextProcessor().context_processor(request),
51     }
52 
53     if getattr(settings, "CDN_DOMAIN", None):
54         context["CDN_DOMAIN"] = settings.CDN_DOMAIN
55 
56     # Add a MEDIA_URL_PREFIX to context to prefix the media url files to have an absolute URL
57     if settings.MEDIA_URL.startswith("//"):
58         # Eg. //my-cdn-user.cdn-provider.com/media/
59         context["MEDIA_URL_PREFIX"] = f"{request.scheme:s}:"
60     elif settings.MEDIA_URL.startswith("/"):
61         # Eg. /media/
62         context["MEDIA_URL_PREFIX"] = f"{protocol:s}://{site_current.domain:s}"
63     else:
64         # Eg. https://my-cdn-user.cdn-provider.com/media/
65         context["MEDIA_URL_PREFIX"] = ""
66 
67     authentication_delegation = getattr(
68         settings, "RICHIE_AUTHENTICATION_DELEGATION", None
69     )
70     if authentication_delegation:
71 
72         context["AUTHENTICATION"] = {
73             "profile_urls": json.dumps(
74                 {
75                     key: {
76                         "label": str(url["label"]),
77                         "action": str(
78                             url["href"].format(
79                                 base_url=authentication_delegation["BASE_URL"]
80                             )
81                         ),
82                     }
83                     for key, url in authentication_delegation.get(
84                         "PROFILE_URLS", {}
85                     ).items()
86                 }
87             ),
88         }
89 
90         context["FRONTEND_CONTEXT"]["context"]["authentication"] = {
91             "endpoint": authentication_delegation["BASE_URL"],
92             "backend": authentication_delegation["BACKEND"],
93         }
94 
95     if getattr(settings, "RICHIE_LMS_BACKENDS", None):
96         context["FRONTEND_CONTEXT"]["context"]["lms_backends"] = [
97             {
98                 "endpoint": lms["BASE_URL"],
99                 "backend": lms["JS_BACKEND"],
100                 "course_regexp": lms["JS_COURSE_REGEX"],
101             }
102             for lms in getattr(settings, "RICHIE_LMS_BACKENDS", [])
103         ]
104 
105     context["FRONTEND_CONTEXT"] = json.dumps(context["FRONTEND_CONTEXT"])
106 
107     if getattr(settings, "RICHIE_MINIMUM_COURSE_RUNS_ENROLLMENT_COUNT", None):
108         context[
109             "RICHIE_MINIMUM_COURSE_RUNS_ENROLLMENT_COUNT"
110         ] = settings.RICHIE_MINIMUM_COURSE_RUNS_ENROLLMENT_COUNT
111 
112     context["RICHIE_MAX_ARCHIVED_COURSE_RUNS"] = getattr(
113         settings, "RICHIE_MAX_ARCHIVED_COURSE_RUNS", RICHIE_MAX_ARCHIVED_COURSE_RUNS
114     )
115 
116     return context
117 
118 
119 class WebAnalyticsContextProcessor:
120     """
121     Context processor to add Web Analytics tracking information to Richie CMS templates and
122     frontend.
123     """
124 
125     def context_processor(self, request: HttpRequest) -> dict:
126         """
127         Real implementation of the context processor for the Web Analytics core app sub-module
128         """
129         context = {}
130         if hasattr(request, "current_page"):
131             # load web analytics settings to the context
132             if getattr(settings, "WEB_ANALYTICS_ID", None):
133                 context["WEB_ANALYTICS_ID"] = settings.WEB_ANALYTICS_ID
134                 context["WEB_ANALYTICS_DIMENSIONS"] = self.get_dimensions(request)
135 
136             context["WEB_ANALYTICS_LOCATION"] = getattr(
137                 settings, "WEB_ANALYTICS_LOCATION", "head"
138             )
139 
140             context["WEB_ANALYTICS_PROVIDER"] = getattr(
141                 settings, "WEB_ANALYTICS_PROVIDER", "google_analytics"
142             )
143         return context
144 
145     # pylint: disable=no-self-use
146     def get_dimensions(self, request: HttpRequest) -> dict:
147         """
148         Compute the web analytics dimensions (dict) that would be added to the Django context
149         They are a dictionary like:
150         ```
151         {
152             "organizations_codes": ["UNIV_LISBON", "UNIV_PORTO"],
153             "course_code": ["COURSE_XPTO"],
154             "course_runs_titles": [
155                 "Summer edition",
156                 "Winter edition"
157             ],
158             "course_runs_resource_links": [
159                 "http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info",
160                 "http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course_2/info"
161             ],
162             "page_title": ["Introduction to Programming"],
163         }
164         ```
165 
166         Args:
167             request (HttpRequest): The Http request
168             web_analytics_context (dict): the context relevant for the web analytics sub module
169 
170         Returns:
171             dict: a dict with the dimensions, where each value is a list
172         """
173         # Warn do not change the order of evaluation of this methods, because on Google Analytics
174         # the key is a 'dimension1' instead of a more generic key like 'organizations'.
175         # That's why we are using an OrderedDict instead of a normal Python dict (don't support
176         # ordering)
177         dimensions = OrderedDict()
178 
179         page = request.current_page or None
180         language = get_language_from_request(request, check_path=True)
181 
182         organizations_codes = []
183         if page and not page.is_home:
184             organizations_codes = Organization.get_organizations_codes(page, language)
185         dimensions["organizations_codes"] = organizations_codes
186 
187         course = getattr(page, "course", None)
188         dimensions["course_code"] = [getattr(course, "code", "")]
189 
190         course_runs = course.course_runs if course else []
191         dimensions["course_runs_titles"] = [
192             course_run.title
193             for course_run in course_runs
194             if course_run is not None and course_run.safe_title is not None
195         ]
196 
197         dimensions["course_runs_resource_links"] = map(
198             lambda course_run: course_run.resource_link, course_runs
199         )
200 
201         dimensions["page_title"] = [page.get_title() if page else ""]
202         return dimensions
203
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/richie/apps/core/context_processors.py b/src/richie/apps/core/context_processors.py
--- a/src/richie/apps/core/context_processors.py
+++ b/src/richie/apps/core/context_processors.py
@@ -6,6 +6,7 @@
 
 from django.conf import settings
 from django.contrib.sites.models import Site
+from django.core.files.storage import get_storage_class
 from django.http.request import HttpRequest
 from django.middleware.csrf import get_token
 from django.utils.translation import get_language_from_request
@@ -53,11 +54,12 @@
     if getattr(settings, "CDN_DOMAIN", None):
         context["CDN_DOMAIN"] = settings.CDN_DOMAIN
 
+    storage_url = get_storage_class()().url("any-page")
     # Add a MEDIA_URL_PREFIX to context to prefix the media url files to have an absolute URL
-    if settings.MEDIA_URL.startswith("//"):
+    if storage_url.startswith("//"):
         # Eg. //my-cdn-user.cdn-provider.com/media/
         context["MEDIA_URL_PREFIX"] = f"{request.scheme:s}:"
-    elif settings.MEDIA_URL.startswith("/"):
+    elif storage_url.startswith("/"):
         # Eg. /media/
         context["MEDIA_URL_PREFIX"] = f"{protocol:s}://{site_current.domain:s}"
     else:

{"golden_diff": "diff --git a/src/richie/apps/core/context_processors.py b/src/richie/apps/core/context_processors.py\n--- a/src/richie/apps/core/context_processors.py\n+++ b/src/richie/apps/core/context_processors.py\n@@ -6,6 +6,7 @@\n \n from django.conf import settings\n from django.contrib.sites.models import Site\n+from django.core.files.storage import get_storage_class\n from django.http.request import HttpRequest\n from django.middleware.csrf import get_token\n from django.utils.translation import get_language_from_request\n@@ -53,11 +54,12 @@\n     if getattr(settings, \"CDN_DOMAIN\", None):\n         context[\"CDN_DOMAIN\"] = settings.CDN_DOMAIN\n \n+    storage_url = get_storage_class()().url(\"any-page\")\n     # Add a MEDIA_URL_PREFIX to context to prefix the media url files to have an absolute URL\n-    if settings.MEDIA_URL.startswith(\"//\"):\n+    if storage_url.startswith(\"//\"):\n         # Eg. //my-cdn-user.cdn-provider.com/media/\n         context[\"MEDIA_URL_PREFIX\"] = f\"{request.scheme:s}:\"\n-    elif settings.MEDIA_URL.startswith(\"/\"):\n+    elif storage_url.startswith(\"/\"):\n         # Eg. /media/\n         context[\"MEDIA_URL_PREFIX\"] = f\"{protocol:s}://{site_current.domain:s}\"\n     else:\n", "issue": "og:image is not set propertly\n## Bug Report\r\n\r\n**Expected behavior/code**\r\nFor SEO purpose, we add open graph tags into CMS pages. These tags should be properly configured.\r\n\r\n**Actual Behavior**\r\nOn CMS Page, `og:image` url is malformed.\r\n\r\n**Steps to Reproduce**\r\n1. Go to a CMS Page\r\n2. Use [facebook debug tool](https://developers.facebook.com/tools/debug/) to check link preview for the CMS Page\r\n3.  Note that `og:image` tag is not valid\r\n\r\n**Environment**\r\n- Richie version: 2.8.2\r\n- Platform: Mac OS 12.0.1 - Firefox 93.0\r\n\r\n**Possible Solution**\r\n- Fix the `og:image` attribute\r\n\r\n**Additional context/Screenshots**\r\n- https://developers.facebook.com/tools/debug/?q=https%3A%2F%2Fwww.fun-mooc.fr%2Ffr%2Fcours%2Fmooc-elles-font-lart%2F\r\n- https://developers.facebook.com/tools/debug/?q=https%3A%2F%2Fwww.fun-mooc.fr%2Ffr%2Factualites%2Fdeveloppement-des-territoires-comment-agir-pour-construire-laven%2F\r\n\n", "before_files": [{"content": "\"\"\"\nTemplate context processors\n\"\"\"\nimport json\nfrom collections import OrderedDict\n\nfrom django.conf import settings\nfrom django.contrib.sites.models import Site\nfrom django.http.request import HttpRequest\nfrom django.middleware.csrf import get_token\nfrom django.utils.translation import get_language_from_request\n\nfrom richie.apps.courses.defaults import RICHIE_MAX_ARCHIVED_COURSE_RUNS\nfrom richie.apps.courses.models import Organization\n\nfrom . import defaults\n\n\ndef site_metas(request: HttpRequest):\n    \"\"\"\n    Context processor to add all information required by Richie CMS templates and frontend.\n\n    If `CDN_DOMAIN` settings is defined we add it in the context. It allows\n    to load statics js on a CDN like cloudfront.\n    \"\"\"\n    site_current = Site.objects.get_current()\n    protocol = \"https\" if request.is_secure() else \"http\"\n\n    context = {\n        **{\n            f\"GLIMPSE_PAGINATION_{k.upper()}\": v\n            for k, v in {\n                **defaults.GLIMPSE_PAGINATION,\n                **getattr(settings, \"RICHIE_GLIMPSE_PAGINATION\", {}),\n            }.items()\n        },\n        \"SITE\": {\n            \"name\": site_current.name,\n            \"domain\": site_current.domain,\n            \"web_url\": f\"{protocol:s}://{site_current.domain:s}\",\n        },\n        \"FRONTEND_CONTEXT\": {\n            \"context\": {\n                \"csrftoken\": get_token(request),\n                \"environment\": getattr(settings, \"ENVIRONMENT\", \"\"),\n                \"release\": getattr(settings, \"RELEASE\", \"\"),\n                \"sentry_dsn\": getattr(settings, \"SENTRY_DSN\", \"\"),\n            }\n        },\n        **WebAnalyticsContextProcessor().context_processor(request),\n    }\n\n    if getattr(settings, \"CDN_DOMAIN\", None):\n        context[\"CDN_DOMAIN\"] = settings.CDN_DOMAIN\n\n    # Add a MEDIA_URL_PREFIX to context to prefix the media url files to have an absolute URL\n    if settings.MEDIA_URL.startswith(\"//\"):\n        # Eg. //my-cdn-user.cdn-provider.com/media/\n        context[\"MEDIA_URL_PREFIX\"] = f\"{request.scheme:s}:\"\n    elif settings.MEDIA_URL.startswith(\"/\"):\n        # Eg. /media/\n        context[\"MEDIA_URL_PREFIX\"] = f\"{protocol:s}://{site_current.domain:s}\"\n    else:\n        # Eg. https://my-cdn-user.cdn-provider.com/media/\n        context[\"MEDIA_URL_PREFIX\"] = \"\"\n\n    authentication_delegation = getattr(\n        settings, \"RICHIE_AUTHENTICATION_DELEGATION\", None\n    )\n    if authentication_delegation:\n\n        context[\"AUTHENTICATION\"] = {\n            \"profile_urls\": json.dumps(\n                {\n                    key: {\n                        \"label\": str(url[\"label\"]),\n                        \"action\": str(\n                            url[\"href\"].format(\n                                base_url=authentication_delegation[\"BASE_URL\"]\n                            )\n                        ),\n                    }\n                    for key, url in authentication_delegation.get(\n                        \"PROFILE_URLS\", {}\n                    ).items()\n                }\n            ),\n        }\n\n        context[\"FRONTEND_CONTEXT\"][\"context\"][\"authentication\"] = {\n            \"endpoint\": authentication_delegation[\"BASE_URL\"],\n            \"backend\": authentication_delegation[\"BACKEND\"],\n        }\n\n    if getattr(settings, \"RICHIE_LMS_BACKENDS\", None):\n        context[\"FRONTEND_CONTEXT\"][\"context\"][\"lms_backends\"] = [\n            {\n                \"endpoint\": lms[\"BASE_URL\"],\n                \"backend\": lms[\"JS_BACKEND\"],\n                \"course_regexp\": lms[\"JS_COURSE_REGEX\"],\n            }\n            for lms in getattr(settings, \"RICHIE_LMS_BACKENDS\", [])\n        ]\n\n    context[\"FRONTEND_CONTEXT\"] = json.dumps(context[\"FRONTEND_CONTEXT\"])\n\n    if getattr(settings, \"RICHIE_MINIMUM_COURSE_RUNS_ENROLLMENT_COUNT\", None):\n        context[\n            \"RICHIE_MINIMUM_COURSE_RUNS_ENROLLMENT_COUNT\"\n        ] = settings.RICHIE_MINIMUM_COURSE_RUNS_ENROLLMENT_COUNT\n\n    context[\"RICHIE_MAX_ARCHIVED_COURSE_RUNS\"] = getattr(\n        settings, \"RICHIE_MAX_ARCHIVED_COURSE_RUNS\", RICHIE_MAX_ARCHIVED_COURSE_RUNS\n    )\n\n    return context\n\n\nclass WebAnalyticsContextProcessor:\n    \"\"\"\n    Context processor to add Web Analytics tracking information to Richie CMS templates and\n    frontend.\n    \"\"\"\n\n    def context_processor(self, request: HttpRequest) -> dict:\n        \"\"\"\n        Real implementation of the context processor for the Web Analytics core app sub-module\n        \"\"\"\n        context = {}\n        if hasattr(request, \"current_page\"):\n            # load web analytics settings to the context\n            if getattr(settings, \"WEB_ANALYTICS_ID\", None):\n                context[\"WEB_ANALYTICS_ID\"] = settings.WEB_ANALYTICS_ID\n                context[\"WEB_ANALYTICS_DIMENSIONS\"] = self.get_dimensions(request)\n\n            context[\"WEB_ANALYTICS_LOCATION\"] = getattr(\n                settings, \"WEB_ANALYTICS_LOCATION\", \"head\"\n            )\n\n            context[\"WEB_ANALYTICS_PROVIDER\"] = getattr(\n                settings, \"WEB_ANALYTICS_PROVIDER\", \"google_analytics\"\n            )\n        return context\n\n    # pylint: disable=no-self-use\n    def get_dimensions(self, request: HttpRequest) -> dict:\n        \"\"\"\n        Compute the web analytics dimensions (dict) that would be added to the Django context\n        They are a dictionary like:\n        ```\n        {\n            \"organizations_codes\": [\"UNIV_LISBON\", \"UNIV_PORTO\"],\n            \"course_code\": [\"COURSE_XPTO\"],\n            \"course_runs_titles\": [\n                \"Summer edition\",\n                \"Winter edition\"\n            ],\n            \"course_runs_resource_links\": [\n                \"http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info\",\n                \"http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course_2/info\"\n            ],\n            \"page_title\": [\"Introduction to Programming\"],\n        }\n        ```\n\n        Args:\n            request (HttpRequest): The Http request\n            web_analytics_context (dict): the context relevant for the web analytics sub module\n\n        Returns:\n            dict: a dict with the dimensions, where each value is a list\n        \"\"\"\n        # Warn do not change the order of evaluation of this methods, because on Google Analytics\n        # the key is a 'dimension1' instead of a more generic key like 'organizations'.\n        # That's why we are using an OrderedDict instead of a normal Python dict (don't support\n        # ordering)\n        dimensions = OrderedDict()\n\n        page = request.current_page or None\n        language = get_language_from_request(request, check_path=True)\n\n        organizations_codes = []\n        if page and not page.is_home:\n            organizations_codes = Organization.get_organizations_codes(page, language)\n        dimensions[\"organizations_codes\"] = organizations_codes\n\n        course = getattr(page, \"course\", None)\n        dimensions[\"course_code\"] = [getattr(course, \"code\", \"\")]\n\n        course_runs = course.course_runs if course else []\n        dimensions[\"course_runs_titles\"] = [\n            course_run.title\n            for course_run in course_runs\n            if course_run is not None and course_run.safe_title is not None\n        ]\n\n        dimensions[\"course_runs_resource_links\"] = map(\n            lambda course_run: course_run.resource_link, course_runs\n        )\n\n        dimensions[\"page_title\"] = [page.get_title() if page else \"\"]\n        return dimensions\n", "path": "src/richie/apps/core/context_processors.py"}], "after_files": [{"content": "\"\"\"\nTemplate context processors\n\"\"\"\nimport json\nfrom collections import OrderedDict\n\nfrom django.conf import settings\nfrom django.contrib.sites.models import Site\nfrom django.core.files.storage import get_storage_class\nfrom django.http.request import HttpRequest\nfrom django.middleware.csrf import get_token\nfrom django.utils.translation import get_language_from_request\n\nfrom richie.apps.courses.defaults import RICHIE_MAX_ARCHIVED_COURSE_RUNS\nfrom richie.apps.courses.models import Organization\n\nfrom . import defaults\n\n\ndef site_metas(request: HttpRequest):\n    \"\"\"\n    Context processor to add all information required by Richie CMS templates and frontend.\n\n    If `CDN_DOMAIN` settings is defined we add it in the context. It allows\n    to load statics js on a CDN like cloudfront.\n    \"\"\"\n    site_current = Site.objects.get_current()\n    protocol = \"https\" if request.is_secure() else \"http\"\n\n    context = {\n        **{\n            f\"GLIMPSE_PAGINATION_{k.upper()}\": v\n            for k, v in {\n                **defaults.GLIMPSE_PAGINATION,\n                **getattr(settings, \"RICHIE_GLIMPSE_PAGINATION\", {}),\n            }.items()\n        },\n        \"SITE\": {\n            \"name\": site_current.name,\n            \"domain\": site_current.domain,\n            \"web_url\": f\"{protocol:s}://{site_current.domain:s}\",\n        },\n        \"FRONTEND_CONTEXT\": {\n            \"context\": {\n                \"csrftoken\": get_token(request),\n                \"environment\": getattr(settings, \"ENVIRONMENT\", \"\"),\n                \"release\": getattr(settings, \"RELEASE\", \"\"),\n                \"sentry_dsn\": getattr(settings, \"SENTRY_DSN\", \"\"),\n            }\n        },\n        **WebAnalyticsContextProcessor().context_processor(request),\n    }\n\n    if getattr(settings, \"CDN_DOMAIN\", None):\n        context[\"CDN_DOMAIN\"] = settings.CDN_DOMAIN\n\n    storage_url = get_storage_class()().url(\"any-page\")\n    # Add a MEDIA_URL_PREFIX to context to prefix the media url files to have an absolute URL\n    if storage_url.startswith(\"//\"):\n        # Eg. //my-cdn-user.cdn-provider.com/media/\n        context[\"MEDIA_URL_PREFIX\"] = f\"{request.scheme:s}:\"\n    elif storage_url.startswith(\"/\"):\n        # Eg. /media/\n        context[\"MEDIA_URL_PREFIX\"] = f\"{protocol:s}://{site_current.domain:s}\"\n    else:\n        # Eg. https://my-cdn-user.cdn-provider.com/media/\n        context[\"MEDIA_URL_PREFIX\"] = \"\"\n\n    authentication_delegation = getattr(\n        settings, \"RICHIE_AUTHENTICATION_DELEGATION\", None\n    )\n    if authentication_delegation:\n\n        context[\"AUTHENTICATION\"] = {\n            \"profile_urls\": json.dumps(\n                {\n                    key: {\n                        \"label\": str(url[\"label\"]),\n                        \"action\": str(\n                            url[\"href\"].format(\n                                base_url=authentication_delegation[\"BASE_URL\"]\n                            )\n                        ),\n                    }\n                    for key, url in authentication_delegation.get(\n                        \"PROFILE_URLS\", {}\n                    ).items()\n                }\n            ),\n        }\n\n        context[\"FRONTEND_CONTEXT\"][\"context\"][\"authentication\"] = {\n            \"endpoint\": authentication_delegation[\"BASE_URL\"],\n            \"backend\": authentication_delegation[\"BACKEND\"],\n        }\n\n    if getattr(settings, \"RICHIE_LMS_BACKENDS\", None):\n        context[\"FRONTEND_CONTEXT\"][\"context\"][\"lms_backends\"] = [\n            {\n                \"endpoint\": lms[\"BASE_URL\"],\n                \"backend\": lms[\"JS_BACKEND\"],\n                \"course_regexp\": lms[\"JS_COURSE_REGEX\"],\n            }\n            for lms in getattr(settings, \"RICHIE_LMS_BACKENDS\", [])\n        ]\n\n    context[\"FRONTEND_CONTEXT\"] = json.dumps(context[\"FRONTEND_CONTEXT\"])\n\n    if getattr(settings, \"RICHIE_MINIMUM_COURSE_RUNS_ENROLLMENT_COUNT\", None):\n        context[\n            \"RICHIE_MINIMUM_COURSE_RUNS_ENROLLMENT_COUNT\"\n        ] = settings.RICHIE_MINIMUM_COURSE_RUNS_ENROLLMENT_COUNT\n\n    context[\"RICHIE_MAX_ARCHIVED_COURSE_RUNS\"] = getattr(\n        settings, \"RICHIE_MAX_ARCHIVED_COURSE_RUNS\", RICHIE_MAX_ARCHIVED_COURSE_RUNS\n    )\n\n    return context\n\n\nclass WebAnalyticsContextProcessor:\n    \"\"\"\n    Context processor to add Web Analytics tracking information to Richie CMS templates and\n    frontend.\n    \"\"\"\n\n    def context_processor(self, request: HttpRequest) -> dict:\n        \"\"\"\n        Real implementation of the context processor for the Web Analytics core app sub-module\n        \"\"\"\n        context = {}\n        if hasattr(request, \"current_page\"):\n            # load web analytics settings to the context\n            if getattr(settings, \"WEB_ANALYTICS_ID\", None):\n                context[\"WEB_ANALYTICS_ID\"] = settings.WEB_ANALYTICS_ID\n                context[\"WEB_ANALYTICS_DIMENSIONS\"] = self.get_dimensions(request)\n\n            context[\"WEB_ANALYTICS_LOCATION\"] = getattr(\n                settings, \"WEB_ANALYTICS_LOCATION\", \"head\"\n            )\n\n            context[\"WEB_ANALYTICS_PROVIDER\"] = getattr(\n                settings, \"WEB_ANALYTICS_PROVIDER\", \"google_analytics\"\n            )\n        return context\n\n    # pylint: disable=no-self-use\n    def get_dimensions(self, request: HttpRequest) -> dict:\n        \"\"\"\n        Compute the web analytics dimensions (dict) that would be added to the Django context\n        They are a dictionary like:\n        ```\n        {\n            \"organizations_codes\": [\"UNIV_LISBON\", \"UNIV_PORTO\"],\n            \"course_code\": [\"COURSE_XPTO\"],\n            \"course_runs_titles\": [\n                \"Summer edition\",\n                \"Winter edition\"\n            ],\n            \"course_runs_resource_links\": [\n                \"http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course/info\",\n                \"http://example.edx:8073/courses/course-v1:edX+DemoX+Demo_Course_2/info\"\n            ],\n            \"page_title\": [\"Introduction to Programming\"],\n        }\n        ```\n\n        Args:\n            request (HttpRequest): The Http request\n            web_analytics_context (dict): the context relevant for the web analytics sub module\n\n        Returns:\n            dict: a dict with the dimensions, where each value is a list\n        \"\"\"\n        # Warn do not change the order of evaluation of this methods, because on Google Analytics\n        # the key is a 'dimension1' instead of a more generic key like 'organizations'.\n        # That's why we are using an OrderedDict instead of a normal Python dict (don't support\n        # ordering)\n        dimensions = OrderedDict()\n\n        page = request.current_page or None\n        language = get_language_from_request(request, check_path=True)\n\n        organizations_codes = []\n        if page and not page.is_home:\n            organizations_codes = Organization.get_organizations_codes(page, language)\n        dimensions[\"organizations_codes\"] = organizations_codes\n\n        course = getattr(page, \"course\", None)\n        dimensions[\"course_code\"] = [getattr(course, \"code\", \"\")]\n\n        course_runs = course.course_runs if course else []\n        dimensions[\"course_runs_titles\"] = [\n            course_run.title\n            for course_run in course_runs\n            if course_run is not None and course_run.safe_title is not None\n        ]\n\n        dimensions[\"course_runs_resource_links\"] = map(\n            lambda course_run: course_run.resource_link, course_runs\n        )\n\n        dimensions[\"page_title\"] = [page.get_title() if page else \"\"]\n        return dimensions\n", "path": "src/richie/apps/core/context_processors.py"}]}