Implement theme admin UI to support previewing
LEARNER-2017
This commit is contained in:
@@ -268,7 +268,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase):
|
||||
self.assertEqual(response.data['developer_message'], u'Parameter usage_id not provided.')
|
||||
|
||||
# Send empty data dictionary.
|
||||
with self.assertNumQueries(7): # No queries for bookmark table.
|
||||
with self.assertNumQueries(8): # No queries for bookmark table.
|
||||
response = self.send_post(
|
||||
client=self.client,
|
||||
url=reverse('bookmarks'),
|
||||
|
||||
@@ -36,13 +36,13 @@ def show_reference_template(request, template):
|
||||
|
||||
# Support dynamic rendering of messages
|
||||
if request.GET.get('alert'):
|
||||
register_info_message(request, request.GET.get('alert'))
|
||||
PageLevelMessages.register_info_message(request, request.GET.get('alert'))
|
||||
if request.GET.get('success'):
|
||||
register_success_message(request, request.GET.get('success'))
|
||||
PageLevelMessages.register_success_message(request, request.GET.get('success'))
|
||||
if request.GET.get('warning'):
|
||||
register_warning_message(request, request.GET.get('warning'))
|
||||
PageLevelMessages.register_warning_message(request, request.GET.get('warning'))
|
||||
if request.GET.get('error'):
|
||||
register_error_message(request, request.GET.get('error'))
|
||||
PageLevelMessages.register_error_message(request, request.GET.get('error'))
|
||||
|
||||
# Add some messages to the course skeleton pages
|
||||
if u'course-skeleton.html' in request.path:
|
||||
|
||||
@@ -8,6 +8,7 @@ from django.conf import settings
|
||||
from django.contrib.staticfiles.storage import staticfiles_storage
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render_to_response
|
||||
from edxmako.shortcuts import is_any_marketing_link_set, is_marketing_link_set, marketing_link
|
||||
from web_fragments.views import FragmentView
|
||||
|
||||
log = logging.getLogger('plugin_api')
|
||||
@@ -17,8 +18,6 @@ class EdxFragmentView(FragmentView):
|
||||
"""
|
||||
The base class of all Open edX fragment views.
|
||||
"""
|
||||
USES_PATTERN_LIBRARY = True
|
||||
|
||||
page_title = None
|
||||
|
||||
@staticmethod
|
||||
@@ -78,6 +77,44 @@ class EdxFragmentView(FragmentView):
|
||||
for js_file in self.js_dependencies():
|
||||
fragment.add_javascript_url(staticfiles_storage.url(js_file))
|
||||
|
||||
def create_base_standalone_context(self, request, fragment, **kwargs):
|
||||
"""
|
||||
Creates the base context for rendering a fragment as a standalone page.
|
||||
"""
|
||||
return {
|
||||
'uses_pattern_library': True,
|
||||
'disable_accordion': True,
|
||||
'allow_iframing': True,
|
||||
'disable_header': True,
|
||||
'disable_footer': True,
|
||||
'disable_window_wrap': True,
|
||||
}
|
||||
|
||||
def _add_studio_standalone_context_variables(self, request, context):
|
||||
"""
|
||||
Adds Studio-specific context variables for fragment standalone pages.
|
||||
|
||||
Note: this is meant to be a temporary hack to ensure that Studio
|
||||
receives the context variables that are expected by some of its
|
||||
shared templates. Ideally these templates shouldn't depend upon
|
||||
this data being provided but should instead import the functionality
|
||||
it needs.
|
||||
"""
|
||||
context.update({
|
||||
'request': request,
|
||||
'settings': settings,
|
||||
'EDX_ROOT_URL': settings.EDX_ROOT_URL,
|
||||
'marketing_link': marketing_link,
|
||||
'is_any_marketing_link_set': is_any_marketing_link_set,
|
||||
'is_marketing_link_set': is_marketing_link_set,
|
||||
})
|
||||
|
||||
def standalone_page_title(self, request, fragment, **kwargs):
|
||||
"""
|
||||
Returns the page title for the standalone page, or None if there is no title.
|
||||
"""
|
||||
return None
|
||||
|
||||
def render_standalone_response(self, request, fragment, **kwargs):
|
||||
"""
|
||||
Renders a standalone page for the specified fragment.
|
||||
@@ -86,14 +123,18 @@ class EdxFragmentView(FragmentView):
|
||||
"""
|
||||
if fragment is None:
|
||||
return HttpResponse(status=204)
|
||||
context = {
|
||||
'uses-pattern-library': self.USES_PATTERN_LIBRARY,
|
||||
context = self.create_base_standalone_context(request, fragment, **kwargs)
|
||||
self._add_studio_standalone_context_variables(request, context)
|
||||
context.update({
|
||||
'settings': settings,
|
||||
'fragment': fragment,
|
||||
'disable_accordion': True,
|
||||
'allow_iframing': True,
|
||||
'disable_header': True,
|
||||
'disable_footer': True,
|
||||
'disable_window_wrap': True,
|
||||
}
|
||||
return render_to_response(settings.STANDALONE_FRAGMENT_VIEW_TEMPLATE, context)
|
||||
'page_title': self.standalone_page_title(request, fragment, **kwargs),
|
||||
})
|
||||
if context.get('uses_pattern_library', False):
|
||||
template = 'fragments/standalone-page-v2.html'
|
||||
elif context.get('uses_bootstrap', False):
|
||||
template = 'fragments/standalone-page-bootstrap.html'
|
||||
else:
|
||||
template = 'fragments/standalone-page-v1.html'
|
||||
|
||||
return render_to_response(template, context)
|
||||
|
||||
@@ -366,6 +366,16 @@ def get_themes(themes_dir=None):
|
||||
return themes
|
||||
|
||||
|
||||
def theme_exists(theme_name, themes_dir=None):
|
||||
"""
|
||||
Returns True if a theme exists with the specified name.
|
||||
"""
|
||||
for theme in get_themes(themes_dir=themes_dir):
|
||||
if theme.theme_dir_name == theme_name:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def get_theme_dirs(themes_dir=None):
|
||||
"""
|
||||
Returns theme dirs in given dirs
|
||||
|
||||
@@ -7,19 +7,25 @@ Note:
|
||||
"""
|
||||
from django.conf import settings
|
||||
|
||||
from openedx.core.djangoapps.theming.models import SiteTheme
|
||||
from .models import SiteTheme
|
||||
from .views import get_user_preview_site_theme
|
||||
|
||||
|
||||
class CurrentSiteThemeMiddleware(object):
|
||||
"""
|
||||
Middleware that sets `site_theme` attribute to request object.
|
||||
"""
|
||||
|
||||
def process_request(self, request):
|
||||
"""
|
||||
fetch Site Theme for the current site and add it to the request object.
|
||||
Set the request's 'site_theme' attribute based upon the current user.
|
||||
"""
|
||||
default_theme = None
|
||||
if settings.DEFAULT_SITE_THEME:
|
||||
default_theme = SiteTheme(site=request.site, theme_dir_name=settings.DEFAULT_SITE_THEME)
|
||||
request.site_theme = SiteTheme.get_theme(request.site, default=default_theme)
|
||||
# Determine if the user has specified a preview site
|
||||
preview_site_theme = get_user_preview_site_theme(request)
|
||||
if preview_site_theme:
|
||||
site_theme = preview_site_theme
|
||||
else:
|
||||
default_theme = None
|
||||
if settings.DEFAULT_SITE_THEME:
|
||||
default_theme = SiteTheme(site=request.site, theme_dir_name=settings.DEFAULT_SITE_THEME)
|
||||
site_theme = SiteTheme.get_theme(request.site, default=default_theme)
|
||||
request.site_theme = site_theme
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""
|
||||
Django models supporting the Comprehensive Theming subsystem
|
||||
"""
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
from django.db import models
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
## mako
|
||||
|
||||
<%page expression_filter="h"/>
|
||||
|
||||
<%namespace name='static' file='../static_content.html'/>
|
||||
|
||||
<%!
|
||||
from django.utils.translation import ugettext as _
|
||||
from openedx.core.djangoapps.theming.helpers import get_themes
|
||||
%>
|
||||
|
||||
<h3>
|
||||
${_("Theming Administration")}
|
||||
</h3>
|
||||
<div>
|
||||
<form class="form" action="${request.path}" method="post">
|
||||
<div class="form-group">
|
||||
<label>${_("Preview Theme")}
|
||||
<select class="form-control" name="preview_theme">
|
||||
<%
|
||||
all_themes = list(get_themes())
|
||||
all_themes.sort(key=lambda x: x.theme_dir_name)
|
||||
current_theme_name = request.site_theme.theme_dir_name if request.site_theme else None
|
||||
%>
|
||||
% for theme in all_themes:
|
||||
<% theme_name = theme.theme_dir_name %>
|
||||
<option value="${theme_name}"${' selected=selected' if theme_name == current_theme_name else ''}>${theme_name}</option>
|
||||
% endfor
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button class="btn btn-primary" type="submit" name="action" value="set_preview_theme">${_("Submit")}</button>
|
||||
<button class="btn btn-secondary" type="submit" name="action" value="reset_preview_theme">${_("Reset")}</button>
|
||||
</div>
|
||||
|
||||
<input type="hidden" name="csrfmiddlewaretoken" value="${ csrf_token }"/>
|
||||
</form>
|
||||
|
||||
<p>See also <a href="/admin">Django admin</a> for more theming settings.</p>
|
||||
</div>
|
||||
@@ -1,14 +1,20 @@
|
||||
"""
|
||||
Tests for middleware for comprehensive themes.
|
||||
"""
|
||||
from mock import Mock
|
||||
from django.test import TestCase, override_settings
|
||||
|
||||
from django.contrib.messages.middleware import MessageMiddleware
|
||||
from django.test import RequestFactory, TestCase, override_settings
|
||||
from django.contrib.sites.models import Site
|
||||
|
||||
from openedx.core.djangoapps.theming.middleware import CurrentSiteThemeMiddleware
|
||||
from student.tests.factories import UserFactory
|
||||
|
||||
from ..views import set_user_preview_site_theme
|
||||
|
||||
TEST_URL = '/test'
|
||||
TEST_THEME_NAME = 'test-theme'
|
||||
|
||||
|
||||
class TestCurrentSiteThemeMiddlewareLMS(TestCase):
|
||||
class TestCurrentSiteThemeMiddleware(TestCase):
|
||||
"""
|
||||
Test theming middleware.
|
||||
"""
|
||||
@@ -16,22 +22,38 @@ class TestCurrentSiteThemeMiddlewareLMS(TestCase):
|
||||
"""
|
||||
Initialize middleware and related objects
|
||||
"""
|
||||
super(TestCurrentSiteThemeMiddlewareLMS, self).setUp()
|
||||
super(TestCurrentSiteThemeMiddleware, self).setUp()
|
||||
|
||||
self.site_theme_middleware = CurrentSiteThemeMiddleware()
|
||||
self.request = Mock()
|
||||
self.request.site, __ = Site.objects.get_or_create(domain="test", name="test")
|
||||
self.request.session = {}
|
||||
self.user = UserFactory.create()
|
||||
|
||||
@override_settings(DEFAULT_SITE_THEME="test-theme")
|
||||
def create_mock_get_request(self):
|
||||
"""
|
||||
Returns a mock GET request.
|
||||
"""
|
||||
request = RequestFactory().get(TEST_URL)
|
||||
self.initialize_mock_request(request)
|
||||
return request
|
||||
|
||||
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)
|
||||
|
||||
@override_settings(DEFAULT_SITE_THEME=TEST_THEME_NAME)
|
||||
def test_default_site_theme(self):
|
||||
"""
|
||||
Test that request.site_theme returns theme defined by DEFAULT_SITE_THEME setting
|
||||
when there is no theme associated with the current site.
|
||||
"""
|
||||
self.assertEqual(self.site_theme_middleware.process_request(self.request), None)
|
||||
self.assertIsNotNone(self.request.site_theme)
|
||||
self.assertEqual(self.request.site_theme.theme_dir_name, "test-theme")
|
||||
request = self.create_mock_get_request()
|
||||
self.assertEqual(self.site_theme_middleware.process_request(request), None)
|
||||
self.assertIsNotNone(request.site_theme)
|
||||
self.assertEqual(request.site_theme.theme_dir_name, TEST_THEME_NAME)
|
||||
|
||||
@override_settings(DEFAULT_SITE_THEME=None)
|
||||
def test_default_site_theme_2(self):
|
||||
@@ -39,5 +61,30 @@ class TestCurrentSiteThemeMiddlewareLMS(TestCase):
|
||||
Test that request.site_theme returns None when there is no theme associated with
|
||||
the current site and DEFAULT_SITE_THEME is also None.
|
||||
"""
|
||||
self.assertEqual(self.site_theme_middleware.process_request(self.request), None)
|
||||
self.assertIsNone(self.request.site_theme)
|
||||
request = self.create_mock_get_request()
|
||||
self.assertEqual(self.site_theme_middleware.process_request(request), None)
|
||||
self.assertIsNone(request.site_theme)
|
||||
|
||||
def test_preview_theme(self):
|
||||
"""
|
||||
Verify that preview themes behaves correctly.
|
||||
"""
|
||||
# First request a preview theme
|
||||
post_request = RequestFactory().post('/test')
|
||||
self.initialize_mock_request(post_request)
|
||||
set_user_preview_site_theme(post_request, TEST_THEME_NAME)
|
||||
|
||||
# Next request a page and verify that the theme is returned
|
||||
get_request = self.create_mock_get_request()
|
||||
self.assertEqual(self.site_theme_middleware.process_request(get_request), None)
|
||||
self.assertEqual(get_request.site_theme.theme_dir_name, TEST_THEME_NAME)
|
||||
|
||||
# Request to reset the theme
|
||||
post_request = RequestFactory().post('/test')
|
||||
self.initialize_mock_request(post_request)
|
||||
set_user_preview_site_theme(post_request, None)
|
||||
|
||||
# Finally verify that no theme is returned
|
||||
get_request = self.create_mock_get_request()
|
||||
self.assertEqual(self.site_theme_middleware.process_request(get_request), None)
|
||||
self.assertIsNone(get_request.site_theme)
|
||||
|
||||
105
openedx/core/djangoapps/theming/tests/test_views.py
Normal file
105
openedx/core/djangoapps/theming/tests/test_views.py
Normal file
@@ -0,0 +1,105 @@
|
||||
"""
|
||||
Tests for comprehensive them
|
||||
"""
|
||||
|
||||
from courseware.tests.factories import GlobalStaffFactory
|
||||
from django.conf import settings
|
||||
from django.contrib.messages.middleware import MessageMiddleware
|
||||
from django.test import TestCase, override_settings
|
||||
from django.contrib.sites.models import Site
|
||||
from openedx.core.djangoapps.theming.middleware import CurrentSiteThemeMiddleware
|
||||
from student.tests.factories import UserFactory
|
||||
|
||||
THEMING_ADMIN_URL = '/theming/admin'
|
||||
TEST_THEME_NAME = 'test-theme'
|
||||
TEST_PASSWORD = 'test'
|
||||
|
||||
|
||||
class TestThemingViews(TestCase):
|
||||
"""
|
||||
Test theming views.
|
||||
"""
|
||||
def setUp(self):
|
||||
"""
|
||||
Initialize middleware and related objects
|
||||
"""
|
||||
super(TestThemingViews, self).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):
|
||||
"""
|
||||
Verify that users have the correct access to preview themes.
|
||||
"""
|
||||
# Anonymous users get redirected to the login page
|
||||
response = self.client.get(THEMING_ADMIN_URL)
|
||||
self.assertRedirects(
|
||||
response,
|
||||
'{login_url}?next={url}'.format(
|
||||
login_url=settings.LOGIN_REDIRECT_URL,
|
||||
url=THEMING_ADMIN_URL,
|
||||
)
|
||||
)
|
||||
|
||||
# Logged in non-global staff get a 404
|
||||
self.client.login(username=self.user.username, password=TEST_PASSWORD)
|
||||
response = self.client.get(THEMING_ADMIN_URL)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
# Global staff can access the page
|
||||
global_staff = GlobalStaffFactory()
|
||||
self.client.login(username=global_staff.username, password=TEST_PASSWORD)
|
||||
response = self.client.get(THEMING_ADMIN_URL)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_preview_theme(self):
|
||||
"""
|
||||
Verify that preview themes behaves correctly.
|
||||
"""
|
||||
global_staff = GlobalStaffFactory()
|
||||
self.client.login(username=global_staff.username, password=TEST_PASSWORD)
|
||||
|
||||
# First request a preview theme
|
||||
post_response = self.client.post(
|
||||
THEMING_ADMIN_URL,
|
||||
{
|
||||
'action': 'set_preview_theme',
|
||||
'preview_theme': TEST_THEME_NAME,
|
||||
}
|
||||
)
|
||||
self.assertRedirects(post_response, THEMING_ADMIN_URL)
|
||||
|
||||
# Next request a page and verify that the correct theme has been chosen
|
||||
response = self.client.get(THEMING_ADMIN_URL)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<option value="{theme_name}" selected=selected>'.format(theme_name=TEST_THEME_NAME)
|
||||
)
|
||||
|
||||
# Request to reset the theme
|
||||
post_response = self.client.post(
|
||||
THEMING_ADMIN_URL,
|
||||
{
|
||||
'action': 'reset_preview_theme'
|
||||
}
|
||||
)
|
||||
self.assertRedirects(post_response, THEMING_ADMIN_URL)
|
||||
|
||||
# Finally verify that the test theme is no longer selected
|
||||
response = self.client.get(THEMING_ADMIN_URL)
|
||||
self.assertEquals(response.status_code, 200)
|
||||
self.assertContains(
|
||||
response,
|
||||
'<option value="{theme_name}">'.format(theme_name=TEST_THEME_NAME)
|
||||
)
|
||||
18
openedx/core/djangoapps/theming/urls.py
Normal file
18
openedx/core/djangoapps/theming/urls.py
Normal file
@@ -0,0 +1,18 @@
|
||||
"""
|
||||
Defines URLs for theming views.
|
||||
"""
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from .helpers import is_comprehensive_theming_enabled
|
||||
from .views import ThemingAdministrationFragmentView
|
||||
|
||||
|
||||
if is_comprehensive_theming_enabled():
|
||||
urlpatterns = [
|
||||
url(
|
||||
r'^admin',
|
||||
ThemingAdministrationFragmentView.as_view(),
|
||||
name='openedx.theming.update_theme_fragment_view',
|
||||
),
|
||||
]
|
||||
135
openedx/core/djangoapps/theming/views.py
Normal file
135
openedx/core/djangoapps/theming/views.py
Normal file
@@ -0,0 +1,135 @@
|
||||
"""
|
||||
Views file for theming administration.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import Http404
|
||||
from django.shortcuts import redirect
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.translation import ugettext as _
|
||||
from openedx.core.djangoapps.plugin_api.views import EdxFragmentView
|
||||
from openedx.core.djangoapps.user_api.preferences.api import (
|
||||
delete_user_preference,
|
||||
get_user_preference,
|
||||
set_user_preference,
|
||||
)
|
||||
from openedx.core.djangoapps.util.user_messages import PageLevelMessages
|
||||
from student.roles import GlobalStaff
|
||||
from web_fragments.fragment import Fragment
|
||||
|
||||
from .helpers import theme_exists
|
||||
from .models import SiteTheme
|
||||
|
||||
PREVIEW_SITE_THEME_PREFERENCE_KEY = 'preview-site-theme'
|
||||
PREVIEW_THEME_FIELD = 'preview_theme'
|
||||
|
||||
|
||||
def user_can_preview_themes(user):
|
||||
"""
|
||||
Returns true if the specified user is allowed to preview themes.
|
||||
"""
|
||||
if not user or user.is_anonymous():
|
||||
return False
|
||||
|
||||
# In development mode, all users can preview themes
|
||||
if settings.DEBUG:
|
||||
return True
|
||||
|
||||
# Otherwise, only global staff can preview themes
|
||||
return GlobalStaff().has_user(user)
|
||||
|
||||
|
||||
def get_user_preview_site_theme(request):
|
||||
"""
|
||||
Returns the preview site for the current user, or None if not set.
|
||||
"""
|
||||
user = request.user
|
||||
if not user or user.is_anonymous():
|
||||
return None
|
||||
preview_site_name = get_user_preference(user, PREVIEW_SITE_THEME_PREFERENCE_KEY)
|
||||
if not preview_site_name:
|
||||
return None
|
||||
return SiteTheme(site=request.site, theme_dir_name=preview_site_name)
|
||||
|
||||
|
||||
def set_user_preview_site_theme(request, preview_site_theme):
|
||||
"""
|
||||
Sets the current user's preferred preview site theme.
|
||||
|
||||
Args:
|
||||
request: the current request
|
||||
preview_site_theme (str or SiteTheme): the preview site theme or theme name.
|
||||
None can be specified to remove the preview site theme.
|
||||
"""
|
||||
if preview_site_theme:
|
||||
if isinstance(preview_site_theme, SiteTheme):
|
||||
preview_site_theme_name = preview_site_theme.theme_dir_name
|
||||
else:
|
||||
preview_site_theme_name = preview_site_theme
|
||||
if theme_exists(preview_site_theme_name):
|
||||
set_user_preference(request.user, PREVIEW_SITE_THEME_PREFERENCE_KEY, preview_site_theme_name)
|
||||
PageLevelMessages.register_success_message(
|
||||
request,
|
||||
_('Site theme changed to {site_theme}'.format(site_theme=preview_site_theme_name))
|
||||
)
|
||||
else:
|
||||
PageLevelMessages.register_error_message(
|
||||
request,
|
||||
_('Theme {site_theme} does not exist'.format(site_theme=preview_site_theme_name))
|
||||
)
|
||||
else:
|
||||
delete_user_preference(request.user, PREVIEW_SITE_THEME_PREFERENCE_KEY)
|
||||
PageLevelMessages.register_success_message(request, _('Site theme reverted to the default'))
|
||||
|
||||
|
||||
class ThemingAdministrationFragmentView(EdxFragmentView):
|
||||
"""
|
||||
Fragment view to allow a user to administer theming.
|
||||
"""
|
||||
|
||||
def render_to_fragment(self, request, course_id=None, **kwargs):
|
||||
"""
|
||||
Renders the theming administration view as a fragment.
|
||||
"""
|
||||
html = render_to_string('theming/theming-admin-fragment.html', {})
|
||||
return Fragment(html)
|
||||
|
||||
@method_decorator(login_required)
|
||||
def get(self, request, *args, **kwargs):
|
||||
"""
|
||||
Renders the theming admin fragment to authorized users.
|
||||
"""
|
||||
if not user_can_preview_themes(request.user):
|
||||
raise Http404
|
||||
return super(ThemingAdministrationFragmentView, self).get(request, *args, **kwargs)
|
||||
|
||||
@method_decorator(login_required)
|
||||
def post(self, request, **kwargs):
|
||||
"""
|
||||
Accept requests to update the theme preview.
|
||||
"""
|
||||
if not user_can_preview_themes(request.user):
|
||||
raise Http404
|
||||
action = request.POST.get('action', None)
|
||||
if action == 'set_preview_theme':
|
||||
preview_theme_name = request.POST.get(PREVIEW_THEME_FIELD, '')
|
||||
set_user_preview_site_theme(request, preview_theme_name)
|
||||
elif action == 'reset_preview_theme':
|
||||
set_user_preview_site_theme(request, None)
|
||||
return redirect(request.path)
|
||||
|
||||
def create_base_standalone_context(self, request, fragment, **kwargs):
|
||||
"""
|
||||
Creates the context to use when rendering a standalone page.
|
||||
"""
|
||||
return {
|
||||
'uses_bootstrap': True,
|
||||
}
|
||||
|
||||
def standalone_page_title(self, request, fragment, **kwargs):
|
||||
"""
|
||||
Returns the page title for the standalone update page.
|
||||
"""
|
||||
return _('Theming Administration')
|
||||
@@ -174,7 +174,7 @@ class TestOwnUsernameAPI(CacheIsolationTestCase, UserAPITestCase):
|
||||
Test that a client (logged in) can get her own username.
|
||||
"""
|
||||
self.client.login(username=self.user.username, password=TEST_PASSWORD)
|
||||
self._verify_get_own_username(14)
|
||||
self._verify_get_own_username(15)
|
||||
|
||||
def test_get_username_inactive(self):
|
||||
"""
|
||||
@@ -184,7 +184,7 @@ class TestOwnUsernameAPI(CacheIsolationTestCase, UserAPITestCase):
|
||||
self.client.login(username=self.user.username, password=TEST_PASSWORD)
|
||||
self.user.is_active = False
|
||||
self.user.save()
|
||||
self._verify_get_own_username(14)
|
||||
self._verify_get_own_username(15)
|
||||
|
||||
def test_get_username_not_logged_in(self):
|
||||
"""
|
||||
@@ -305,7 +305,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
|
||||
"""
|
||||
self.different_client.login(username=self.different_user.username, password=TEST_PASSWORD)
|
||||
self.create_mock_profile(self.user)
|
||||
with self.assertNumQueries(18):
|
||||
with self.assertNumQueries(19):
|
||||
response = self.send_get(self.different_client)
|
||||
self._verify_full_shareable_account_response(response, account_privacy=ALL_USERS_VISIBILITY)
|
||||
|
||||
@@ -320,7 +320,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
|
||||
"""
|
||||
self.different_client.login(username=self.different_user.username, password=TEST_PASSWORD)
|
||||
self.create_mock_profile(self.user)
|
||||
with self.assertNumQueries(18):
|
||||
with self.assertNumQueries(19):
|
||||
response = self.send_get(self.different_client)
|
||||
self._verify_private_account_response(response, account_privacy=PRIVATE_VISIBILITY)
|
||||
|
||||
@@ -395,12 +395,12 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
|
||||
self.assertEqual(False, data["accomplishments_shared"])
|
||||
|
||||
self.client.login(username=self.user.username, password=TEST_PASSWORD)
|
||||
verify_get_own_information(16)
|
||||
verify_get_own_information(17)
|
||||
|
||||
# Now make sure that the user can get the same information, even if not active
|
||||
self.user.is_active = False
|
||||
self.user.save()
|
||||
verify_get_own_information(10)
|
||||
verify_get_own_information(11)
|
||||
|
||||
def test_get_account_empty_string(self):
|
||||
"""
|
||||
@@ -414,7 +414,7 @@ class TestAccountsAPI(CacheIsolationTestCase, UserAPITestCase):
|
||||
legacy_profile.save()
|
||||
|
||||
self.client.login(username=self.user.username, password=TEST_PASSWORD)
|
||||
with self.assertNumQueries(16):
|
||||
with self.assertNumQueries(17):
|
||||
response = self.send_get(self.client)
|
||||
for empty_field in ("level_of_education", "gender", "country", "bio"):
|
||||
self.assertIsNone(response.data[empty_field])
|
||||
|
||||
@@ -8,6 +8,7 @@ from django.core.urlresolvers import reverse
|
||||
from django.shortcuts import render_to_response
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.views.decorators.cache import cache_control
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.views.generic import View
|
||||
@@ -80,3 +81,9 @@ class CourseBookmarksFragmentView(EdxFragmentView):
|
||||
self.add_fragment_resource_urls(fragment)
|
||||
fragment.add_javascript(inline_js)
|
||||
return fragment
|
||||
|
||||
def standalone_page_title(self, request, fragment, **kwargs):
|
||||
"""
|
||||
Returns the standalone page title.
|
||||
"""
|
||||
return _('Bookmarks')
|
||||
|
||||
@@ -160,7 +160,7 @@ class TestCourseHomePage(CourseHomePageTestCase):
|
||||
course_home_url(self.course)
|
||||
|
||||
# Fetch the view and verify the query counts
|
||||
with self.assertNumQueries(37, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
|
||||
with self.assertNumQueries(38, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
|
||||
with check_mongo_calls(4):
|
||||
url = course_home_url(self.course)
|
||||
self.client.get(url)
|
||||
|
||||
@@ -127,7 +127,7 @@ class TestCourseUpdatesPage(SharedModuleStoreTestCase):
|
||||
course_updates_url(self.course)
|
||||
|
||||
# Fetch the view and verify that the query counts haven't changed
|
||||
with self.assertNumQueries(30, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
|
||||
with self.assertNumQueries(31, table_blacklist=QUERY_COUNT_TABLE_BLACKLIST):
|
||||
with check_mongo_calls(4):
|
||||
url = course_updates_url(self.course)
|
||||
self.client.get(url)
|
||||
|
||||
Reference in New Issue
Block a user