Repository: openfun/richie

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



Discussion:

Resolving patch:
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 @@ def site_metas(request: HttpRequest):
     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:


Test patch:
diff --git a/tests/apps/courses/test_templates_course_detail_opengraph.py b/tests/apps/courses/test_templates_course_detail_opengraph.py
--- a/tests/apps/courses/test_templates_course_detail_opengraph.py
+++ b/tests/apps/courses/test_templates_course_detail_opengraph.py
@@ -2,7 +2,9 @@
 Test suite for the Open Graph for course pages
 """
 import re
+from unittest import mock
 
+from django.core.files.storage import FileSystemStorage
 from django.test.utils import override_settings
 
 from cms.api import add_plugin
@@ -185,3 +187,82 @@ def test_open_graph_course_description_no_introduction(self):
         response = self.client.get(url)
 
         self.assertNotContains(response, "og:description")
+
+    @mock.patch.object(
+        FileSystemStorage,
+        "url",
+        lambda storage_instance, name: f"https://test-bucket.s3.amazonaws.com/{name:s}",
+    )
+    def test_open_graph_course_meta_og_image_media_storage_url_full(self):
+        """
+        Test if the og:image of a course has the correct value when using a mocked django storage
+        where each file is served from a AWS S3 URL like S3Boto3Storage.
+        """
+        course = CourseFactory(
+            page_title="Introduction to Programming",
+            code="IntroProg",
+            page_languages=["en"],
+            fill_cover=True,
+        )
+        course_page = course.extended_object
+        course_page.publish("en")
+
+        url = course_page.get_absolute_url(language="en")
+        response = self.client.get(url)
+        response_content = response.content.decode("UTF-8")
+
+        match = re.search("<meta[^>]+og:image[^>]+>", response_content)
+        html_meta_og_image = match.group(0)
+        self.assertIn(
+            'content="https://test-bucket.s3.amazonaws.com/', html_meta_og_image
+        )
+
+    @mock.patch.object(
+        FileSystemStorage,
+        "url",
+        lambda storage_instance, name: f"//my-cdn-user.cdn-provider.com/media/{name:s}",
+    )
+    def test_open_graph_course_meta_og_image_media_storage_url_double_slash(self):
+        """
+        Test if the og:image of a course has the correct value when using a mocked django storage
+        where each file is served storage that generate URLs starting with a double slash.
+        """
+        course = CourseFactory(
+            fill_cover=True,
+        )
+        course_page = course.extended_object
+        course_page.publish("en")
+
+        url = course_page.get_absolute_url(language="en")
+        response = self.client.get(url)
+        response_content = response.content.decode("UTF-8")
+
+        match = re.search("<meta[^>]+og:image[^>]+>", response_content)
+        html_meta_og_image = match.group(0)
+        self.assertIn(
+            'content="http://my-cdn-user.cdn-provider.com/media/', html_meta_og_image
+        )
+
+    @mock.patch.object(
+        FileSystemStorage,
+        "url",
+        lambda storage_instance, name: f"/media/{name:s}",
+    )
+    def test_open_graph_course_meta_og_image_media_storage_url_relative(self):
+        """
+        Test if the og:image of a course has the correct value when using a mocked django storage
+        where each file is served from relative path.
+        """
+        course = CourseFactory(
+            fill_cover=True,
+        )
+        course_page = course.extended_object
+        course_page.publish("en")
+
+        url = course_page.get_absolute_url(language="en")
+        response = self.client.get(url)
+        response_content = response.content.decode("UTF-8")
+
+        match = re.search("<meta[^>]+og:image[^>]+>", response_content)
+        html_meta_og_image = match.group(0)
+        self.assertIn('content="http://example.com/media/', html_meta_og_image)