Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: theme-agnostic view to fetch theme assets #29503

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 27 additions & 24 deletions openedx/core/djangoapps/theming/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
"""
Tests for comprehensive them
"""

from unittest.mock import patch

from django.conf import settings
from django.contrib.messages.middleware import MessageMiddleware
from django.contrib.sites.models import Site
from django.test import TestCase
from django.test import TestCase, override_settings
from django.urls import reverse

from common.djangoapps.student.tests.factories import GlobalStaffFactory
from openedx.core.djangoapps.theming.middleware import CurrentSiteThemeMiddleware
from common.djangoapps.student.tests.factories import UserFactory
from common.djangoapps.student.tests.factories import GlobalStaffFactory, UserFactory
from openedx.core.djangoapps.theming.models import SiteTheme

THEMING_ADMIN_URL = '/theming/admin'
TEST_THEME_NAME = 'test-theme'
Expand All @@ -21,23 +20,6 @@ class TestThemingViews(TestCase):
"""
Test theming views.
"""
def setUp(self):
"""
Initialize middleware and related objects
"""
super().setUp()

self.site_theme_middleware = CurrentSiteThemeMiddleware()
self.user = UserFactory.create()

def initialize_mock_request(self, request):
"""
Initialize a test request.
"""
request.user = self.user
request.site, __ = Site.objects.get_or_create(domain='test', name='test')
request.session = {}
MessageMiddleware().process_request(request)

def test_preview_theme_access(self):
"""
Expand All @@ -57,7 +39,8 @@ def test_preview_theme_access(self):
)

# Logged in non-global staff get a 404
self.client.login(username=self.user.username, password=TEST_PASSWORD)
non_global_staff_user = UserFactory.create()
self.client.login(username=non_global_staff_user.username, password=TEST_PASSWORD)
response = self.client.get(THEMING_ADMIN_URL)
assert response.status_code == 404

Expand Down Expand Up @@ -108,3 +91,23 @@ def test_preview_theme(self):
response,
f'<option value="{TEST_THEME_NAME}">'
)

def test_asset_no_theme(self):
"""
Fetch theme asset when no theme is set.
"""
response = self.client.get(reverse("theming:openedx.theming.asset", kwargs={"path": "images/logo.png"}))
assert response.status_code == 302
assert response.url == "/static/images/logo.png"

@override_settings(STATICFILES_STORAGE="openedx.core.storage.DevelopmentStorage")
def test_asset_with_theme(self):
"""
Fetch theme asset when a theme is set.
"""
SiteTheme.objects.create(site=Site.objects.get(), theme_dir_name="red-theme")
with patch("openedx.core.storage.DevelopmentStorage.themed") as mock_is_themed:
response = self.client.get(reverse("theming:openedx.theming.asset", kwargs={"path": "images/logo.png"}))
mock_is_themed.assert_called_once_with("images/logo.png", "red-theme")
assert response.status_code == 302
assert response.url == "/static/red-theme/images/logo.png"
27 changes: 17 additions & 10 deletions openedx/core/djangoapps/theming/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,26 @@


from django.conf.urls import url
from django.urls import path

from .helpers import is_comprehensive_theming_enabled
from .views import ThemingAdministrationFragmentView
from . import helpers
from . import views

app_name = 'openedx.core.djangoapps.theming'
app_name = "openedx.core.djangoapps.theming"

if is_comprehensive_theming_enabled():
urlpatterns = [
urlpatterns = [
path(
"asset/<path:path>",
views.themed_asset,
name="openedx.theming.asset",
),
]

if helpers.is_comprehensive_theming_enabled():
urlpatterns += [
url(
r'^admin',
ThemingAdministrationFragmentView.as_view(),
name='openedx.theming.update_theme_fragment_view',
r"^admin",
views.ThemingAdministrationFragmentView.as_view(),
name="openedx.theming.update_theme_fragment_view",
),
]
else:
urlpatterns = []
16 changes: 16 additions & 0 deletions openedx/core/djangoapps/theming/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from common.djangoapps.student.roles import GlobalStaff

from .helpers import theme_exists
from .helpers_static import get_static_file_url
from .models import SiteTheme

PREVIEW_SITE_THEME_PREFERENCE_KEY = 'preview-site-theme'
Expand Down Expand Up @@ -135,3 +136,18 @@ def standalone_page_title(self, request, fragment, **kwargs):
Returns the page title for the standalone update page.
"""
return _('Theming Administration')


def themed_asset(request, path):
"""
Redirect to themed asset.

This view makes it easy to link to theme assets without knowing what is the
currently enabled theme. For instance, applications outside of the LMS may
want to link to the LMS logo.

Note that the redirect is not permanent because the theme may change from
one run to the next.
"""
themed_url = get_static_file_url(path)
return redirect(themed_url, permanent=False)