feat: adds waffle flags for legacy libraries v1 and new libraries v2 (#35576)
* refactor: rename CourseHomeSerializer to StudioHomeSerializer to better reflect how this serializer/API is used in the Authoring MFE * feat: adds waffle flags for legacy libraries v1 and new libraries v2 in new Studio Home These waffle flags replace the MFE env flag LIBRARY_MODE. * refactor: use contentstore.toggles.libraries_v1_enabled() and ENABLE_CONTENT_LIBRARIES feature toggle where possible. ENABLE_CONTENT_LIBRARIES has been incorporated into both the libraries_v1_enabled() and libraries_v2_enabled() toggles: FEATURES['ENABLE_CONTENT_LIBRARIES'] must be true for either version of libraries to be "enabled".
This commit is contained in:
@@ -8,7 +8,7 @@ from .course_rerun import CourseRerunSerializer
|
||||
from .course_team import CourseTeamSerializer
|
||||
from .grading import CourseGradingModelSerializer, CourseGradingSerializer
|
||||
from .group_configurations import CourseGroupConfigurationsSerializer
|
||||
from .home import CourseHomeSerializer, CourseHomeTabSerializer, LibraryTabSerializer
|
||||
from .home import StudioHomeSerializer, CourseHomeTabSerializer, LibraryTabSerializer
|
||||
from .proctoring import (
|
||||
LimitedProctoredExamSettingsSerializer,
|
||||
ProctoredExamConfigurationSerializer,
|
||||
|
||||
@@ -41,8 +41,8 @@ class LibraryTabSerializer(serializers.Serializer):
|
||||
libraries = LibraryViewSerializer(many=True, required=False, allow_null=True)
|
||||
|
||||
|
||||
class CourseHomeSerializer(serializers.Serializer):
|
||||
"""Serializer for course home"""
|
||||
class StudioHomeSerializer(serializers.Serializer):
|
||||
"""Serializer for Studio home"""
|
||||
allow_course_reruns = serializers.BooleanField()
|
||||
allow_to_create_new_org = serializers.BooleanField()
|
||||
allow_unicode_course_id = serializers.BooleanField()
|
||||
@@ -58,6 +58,8 @@ class CourseHomeSerializer(serializers.Serializer):
|
||||
in_process_course_actions = UnsucceededCourseSerializer(many=True, required=False, allow_null=True)
|
||||
libraries = LibraryViewSerializer(many=True, required=False, allow_null=True)
|
||||
libraries_enabled = serializers.BooleanField()
|
||||
libraries_v1_enabled = serializers.BooleanField()
|
||||
libraries_v2_enabled = serializers.BooleanField()
|
||||
taxonomies_enabled = serializers.BooleanField()
|
||||
taxonomy_list_mfe_url = serializers.CharField()
|
||||
optimization_enabled = serializers.BooleanField()
|
||||
|
||||
@@ -8,7 +8,7 @@ from rest_framework.views import APIView
|
||||
from openedx.core.lib.api.view_utils import view_auth_classes
|
||||
|
||||
from ....utils import get_home_context, get_course_context, get_library_context
|
||||
from ..serializers import CourseHomeSerializer, CourseHomeTabSerializer, LibraryTabSerializer
|
||||
from ..serializers import StudioHomeSerializer, CourseHomeTabSerializer, LibraryTabSerializer
|
||||
|
||||
|
||||
@view_auth_classes(is_authenticated=True)
|
||||
@@ -24,7 +24,7 @@ class HomePageView(APIView):
|
||||
description="Query param to filter by course org",
|
||||
)],
|
||||
responses={
|
||||
200: CourseHomeSerializer,
|
||||
200: StudioHomeSerializer,
|
||||
401: "The requester is not authenticated.",
|
||||
},
|
||||
)
|
||||
@@ -59,6 +59,9 @@ class HomePageView(APIView):
|
||||
"in_process_course_actions": [],
|
||||
"libraries": [],
|
||||
"libraries_enabled": true,
|
||||
"libraries_v1_enabled": true,
|
||||
"libraries_v2_enabled": true,
|
||||
"library_authoring_mfe_url": "//localhost:3001/course/course-v1:edX+P315+2T2023",
|
||||
"optimization_enabled": true,
|
||||
"request_course_creator_url": "/request_course_creator",
|
||||
"rerun_creator_status": true,
|
||||
@@ -84,7 +87,7 @@ class HomePageView(APIView):
|
||||
'platform_name': settings.PLATFORM_NAME,
|
||||
'user_is_active': request.user.is_active,
|
||||
})
|
||||
serializer = CourseHomeSerializer(home_context)
|
||||
serializer = StudioHomeSerializer(home_context)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
|
||||
@@ -33,12 +33,7 @@ class HomePageViewTest(CourseTestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.url = reverse("cms.djangoapps.contentstore:v1:home")
|
||||
|
||||
def test_home_page_courses_response(self):
|
||||
"""Check successful response content"""
|
||||
response = self.client.get(self.url)
|
||||
|
||||
expected_response = {
|
||||
self.expected_response = {
|
||||
"allow_course_reruns": True,
|
||||
"allow_to_create_new_org": False,
|
||||
"allow_unicode_course_id": False,
|
||||
@@ -51,6 +46,8 @@ class HomePageViewTest(CourseTestCase):
|
||||
"in_process_course_actions": [],
|
||||
"libraries": [],
|
||||
"libraries_enabled": True,
|
||||
"libraries_v1_enabled": True,
|
||||
"libraries_v2_enabled": False,
|
||||
"taxonomies_enabled": True,
|
||||
"taxonomy_list_mfe_url": 'http://course-authoring-mfe/taxonomies',
|
||||
"optimization_enabled": False,
|
||||
@@ -66,6 +63,21 @@ class HomePageViewTest(CourseTestCase):
|
||||
"user_is_active": True,
|
||||
}
|
||||
|
||||
def test_home_page_studio_response(self):
|
||||
"""Check successful response content"""
|
||||
response = self.client.get(self.url)
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertDictEqual(self.expected_response, response.data)
|
||||
|
||||
@override_settings(MEILISEARCH_ENABLED=True)
|
||||
def test_home_page_studio_with_meilisearch_enabled(self):
|
||||
"""Check response content when Meilisearch is enabled"""
|
||||
response = self.client.get(self.url)
|
||||
|
||||
expected_response = self.expected_response
|
||||
expected_response["libraries_v2_enabled"] = True
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertDictEqual(expected_response, response.data)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
CMS feature toggles.
|
||||
"""
|
||||
from edx_toggles.toggles import SettingDictToggle, WaffleFlag
|
||||
from openedx.core.djangoapps.content.search import api as search_api
|
||||
from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag
|
||||
|
||||
# .. toggle_name: FEATURES['ENABLE_EXPORT_GIT']
|
||||
@@ -593,3 +594,76 @@ def default_enable_flexible_peer_openassessments(course_key):
|
||||
level to opt in/out of rolling forward this feature.
|
||||
"""
|
||||
return DEFAULT_ENABLE_FLEXIBLE_PEER_OPENASSESSMENTS.is_enabled(course_key)
|
||||
|
||||
|
||||
# .. toggle_name: FEATURES['ENABLE_CONTENT_LIBRARIES']
|
||||
# .. toggle_implementation: SettingDictToggle
|
||||
# .. toggle_default: True
|
||||
# .. toggle_description: Enables use of the legacy and v2 libraries waffle flags.
|
||||
# Note that legacy content libraries are only supported in courses using split mongo.
|
||||
# .. toggle_use_cases: open_edx
|
||||
# .. toggle_creation_date: 2015-03-06
|
||||
# .. toggle_target_removal_date: 2025-04-09
|
||||
# .. toggle_warning: This flag is deprecated in Sumac, and will be removed in favor of the disable_legacy_libraries and
|
||||
# disable_new_libraries waffle flags.
|
||||
ENABLE_CONTENT_LIBRARIES = SettingDictToggle(
|
||||
"FEATURES", "ENABLE_CONTENT_LIBRARIES", default=True, module_name=__name__
|
||||
)
|
||||
|
||||
# .. toggle_name: contentstore.new_studio_mfe.disable_legacy_libraries
|
||||
# .. toggle_implementation: WaffleFlag
|
||||
# .. toggle_default: False
|
||||
# .. toggle_description: Hides legacy (v1) Libraries tab in Authoring MFE.
|
||||
# This toggle interacts with ENABLE_CONTENT_LIBRARIES toggle: if this is disabled, then legacy libraries are also
|
||||
# disabled.
|
||||
# .. toggle_use_cases: open_edx
|
||||
# .. toggle_creation_date: 2024-10-02
|
||||
# .. toggle_target_removal_date: 2025-04-09
|
||||
# .. toggle_tickets: https://github.com/openedx/frontend-app-authoring/issues/1334
|
||||
# .. toggle_warning: Legacy libraries are deprecated in Sumac, cf https://github.com/openedx/edx-platform/issues/32457
|
||||
DISABLE_LEGACY_LIBRARIES = WaffleFlag(
|
||||
f'{CONTENTSTORE_NAMESPACE}.new_studio_mfe.disable_legacy_libraries',
|
||||
__name__,
|
||||
CONTENTSTORE_LOG_PREFIX,
|
||||
)
|
||||
|
||||
|
||||
def libraries_v1_enabled():
|
||||
"""
|
||||
Returns a boolean if Libraries V2 is enabled in the new Studio Home.
|
||||
"""
|
||||
return (
|
||||
ENABLE_CONTENT_LIBRARIES.is_enabled() and
|
||||
not DISABLE_LEGACY_LIBRARIES.is_enabled()
|
||||
)
|
||||
|
||||
|
||||
# .. toggle_name: contentstore.new_studio_mfe.disable_new_libraries
|
||||
# .. toggle_implementation: WaffleFlag
|
||||
# .. toggle_default: False
|
||||
# .. toggle_description: Hides new Libraries v2 tab in Authoring MFE.
|
||||
# This toggle interacts with settings.MEILISEARCH_ENABLED and ENABLE_CONTENT_LIBRARIES toggle: if these flags are
|
||||
# False, then v2 libraries are also disabled.
|
||||
# .. toggle_use_cases: open_edx
|
||||
# .. toggle_creation_date: 2024-10-02
|
||||
# .. toggle_target_removal_date: 2025-04-09
|
||||
# .. toggle_tickets: https://github.com/openedx/frontend-app-authoring/issues/1334
|
||||
# .. toggle_warning: Libraries v2 are in beta for Sumac, will be fully supported in Teak.
|
||||
DISABLE_NEW_LIBRARIES = WaffleFlag(
|
||||
f'{CONTENTSTORE_NAMESPACE}.new_studio_mfe.disable_new_libraries',
|
||||
__name__,
|
||||
CONTENTSTORE_LOG_PREFIX,
|
||||
)
|
||||
|
||||
|
||||
def libraries_v2_enabled():
|
||||
"""
|
||||
Returns a boolean if Libraries V2 is enabled in the new Studio Home.
|
||||
|
||||
Requires the ENABLE_CONTENT_LIBRARIES feature flag to be enabled, plus Meilisearch.
|
||||
"""
|
||||
return (
|
||||
ENABLE_CONTENT_LIBRARIES.is_enabled() and
|
||||
search_api.is_meilisearch_enabled() and
|
||||
not DISABLE_NEW_LIBRARIES.is_enabled()
|
||||
)
|
||||
|
||||
@@ -34,7 +34,11 @@ from milestones import api as milestones_api
|
||||
from pytz import UTC
|
||||
from xblock.fields import Scope
|
||||
|
||||
from cms.djangoapps.contentstore.toggles import exam_setting_view_enabled
|
||||
from cms.djangoapps.contentstore.toggles import (
|
||||
exam_setting_view_enabled,
|
||||
libraries_v1_enabled,
|
||||
libraries_v2_enabled,
|
||||
)
|
||||
from common.djangoapps.course_action_state.models import CourseRerunUIStateManager, CourseRerunState
|
||||
from common.djangoapps.course_action_state.managers import CourseActionStateItemNotFoundError
|
||||
from common.djangoapps.course_modes.models import CourseMode
|
||||
@@ -1536,11 +1540,10 @@ def get_library_context(request, request_is_json=False):
|
||||
_format_library_for_view,
|
||||
)
|
||||
from cms.djangoapps.contentstore.views.library import (
|
||||
LIBRARIES_ENABLED,
|
||||
user_can_view_create_library_button,
|
||||
)
|
||||
|
||||
libraries = _accessible_libraries_iter(request.user) if LIBRARIES_ENABLED else []
|
||||
libraries = _accessible_libraries_iter(request.user) if libraries_v1_enabled() else []
|
||||
data = {
|
||||
'libraries': [_format_library_for_view(lib, request) for lib in libraries],
|
||||
}
|
||||
@@ -1550,7 +1553,7 @@ def get_library_context(request, request_is_json=False):
|
||||
**data,
|
||||
'in_process_course_actions': [],
|
||||
'courses': [],
|
||||
'libraries_enabled': LIBRARIES_ENABLED,
|
||||
'libraries_enabled': libraries_v1_enabled(),
|
||||
'show_new_library_button': user_can_view_create_library_button(request.user) and request.user.is_active,
|
||||
'user': request.user,
|
||||
'request_course_creator_url': reverse('request_course_creator'),
|
||||
@@ -1671,7 +1674,6 @@ def get_home_context(request, no_course=False):
|
||||
ENABLE_GLOBAL_STAFF_OPTIMIZATION,
|
||||
)
|
||||
from cms.djangoapps.contentstore.views.library import (
|
||||
LIBRARIES_ENABLED,
|
||||
user_can_view_create_library_button,
|
||||
)
|
||||
|
||||
@@ -1687,7 +1689,7 @@ def get_home_context(request, no_course=False):
|
||||
if not no_course:
|
||||
active_courses, archived_courses, in_process_course_actions = get_course_context(request)
|
||||
|
||||
if not split_library_view_on_dashboard() and LIBRARIES_ENABLED and not no_course:
|
||||
if not split_library_view_on_dashboard() and libraries_v1_enabled() and not no_course:
|
||||
libraries = get_library_context(request, True)['libraries']
|
||||
|
||||
home_context = {
|
||||
@@ -1695,7 +1697,9 @@ def get_home_context(request, no_course=False):
|
||||
'split_studio_home': split_library_view_on_dashboard(),
|
||||
'archived_courses': archived_courses,
|
||||
'in_process_course_actions': in_process_course_actions,
|
||||
'libraries_enabled': LIBRARIES_ENABLED,
|
||||
'libraries_enabled': libraries_v1_enabled(),
|
||||
'libraries_v1_enabled': libraries_v1_enabled(),
|
||||
'libraries_v2_enabled': libraries_v2_enabled(),
|
||||
'taxonomies_enabled': not is_tagging_feature_disabled(),
|
||||
'taxonomy_list_mfe_url': get_taxonomy_list_url(),
|
||||
'libraries': libraries,
|
||||
|
||||
@@ -42,6 +42,7 @@ from common.djangoapps.student.roles import (
|
||||
from common.djangoapps.util.json_request import JsonResponse, JsonResponseBadRequest, expect_json
|
||||
|
||||
from ..utils import add_instructor, reverse_library_url
|
||||
from ..toggles import libraries_v1_enabled
|
||||
from .component import CONTAINER_TEMPLATES, get_component_templates
|
||||
from cms.djangoapps.contentstore.xblock_storage_handlers.view_handlers import create_xblock_info
|
||||
from .user import user_with_role
|
||||
@@ -50,13 +51,11 @@ __all__ = ['library_handler', 'manage_library_users']
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
LIBRARIES_ENABLED = settings.FEATURES.get('ENABLE_CONTENT_LIBRARIES', False)
|
||||
|
||||
|
||||
def _user_can_create_library_for_org(user, org=None):
|
||||
"""
|
||||
Helper method for returning the library creation status for a particular user,
|
||||
taking into account the value LIBRARIES_ENABLED.
|
||||
taking into account the libraries_v1_enabled toggle.
|
||||
|
||||
if the ENABLE_CREATOR_GROUP value is False, then any user can create a library (in any org),
|
||||
if library creation is enabled.
|
||||
@@ -69,7 +68,7 @@ def _user_can_create_library_for_org(user, org=None):
|
||||
Course Staff: Can make libraries in the organization which has courses of which they are staff.
|
||||
Course Admin: Can make libraries in the organization which has courses of which they are Admin.
|
||||
"""
|
||||
if not LIBRARIES_ENABLED:
|
||||
if not libraries_v1_enabled():
|
||||
return False
|
||||
elif user.is_staff:
|
||||
return True
|
||||
@@ -125,7 +124,7 @@ def library_handler(request, library_key_string=None):
|
||||
"""
|
||||
RESTful interface to most content library related functionality.
|
||||
"""
|
||||
if not LIBRARIES_ENABLED:
|
||||
if not libraries_v1_enabled():
|
||||
log.exception("Attempted to use the content library API when the libraries feature is disabled.")
|
||||
raise Http404 # Should never happen because we test the feature in urls.py also
|
||||
|
||||
|
||||
@@ -56,44 +56,44 @@ class UnitTestLibraries(CourseTestCase):
|
||||
# Tests for /library/ - list and create libraries:
|
||||
|
||||
# When libraries are disabled, nobody can create libraries
|
||||
@mock.patch("cms.djangoapps.contentstore.views.library.LIBRARIES_ENABLED", False)
|
||||
@mock.patch("cms.djangoapps.contentstore.toggles.libraries_v1_enabled", False)
|
||||
def test_library_creator_status_libraries_not_enabled(self):
|
||||
_, nostaff_user = self.create_non_staff_authed_user_client()
|
||||
self.assertEqual(user_can_create_library(nostaff_user, None), False)
|
||||
|
||||
# When creator group is disabled, non-staff users can create libraries
|
||||
@mock.patch("cms.djangoapps.contentstore.views.library.LIBRARIES_ENABLED", True)
|
||||
@mock.patch("cms.djangoapps.contentstore.toggles.libraries_v1_enabled", True)
|
||||
def test_library_creator_status_with_no_course_creator_role(self):
|
||||
_, nostaff_user = self.create_non_staff_authed_user_client()
|
||||
self.assertEqual(user_can_create_library(nostaff_user, 'An Org'), True)
|
||||
|
||||
# When creator group is enabled, Non staff users cannot create libraries
|
||||
@mock.patch("cms.djangoapps.contentstore.views.library.LIBRARIES_ENABLED", True)
|
||||
@mock.patch("cms.djangoapps.contentstore.toggles.libraries_v1_enabled", True)
|
||||
def test_library_creator_status_for_enabled_creator_group_setting_for_non_staff_users(self):
|
||||
_, nostaff_user = self.create_non_staff_authed_user_client()
|
||||
with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}):
|
||||
self.assertEqual(user_can_create_library(nostaff_user, None), False)
|
||||
|
||||
# Global staff can create libraries for any org, even ones that don't exist.
|
||||
@mock.patch("cms.djangoapps.contentstore.views.library.LIBRARIES_ENABLED", True)
|
||||
@mock.patch("cms.djangoapps.contentstore.toggles.libraries_v1_enabled", True)
|
||||
def test_library_creator_status_with_is_staff_user(self):
|
||||
print(self.user.is_staff)
|
||||
self.assertEqual(user_can_create_library(self.user, 'aNyOrg'), True)
|
||||
|
||||
# Global staff can create libraries for any org, but an org has to be supplied.
|
||||
@mock.patch("cms.djangoapps.contentstore.views.library.LIBRARIES_ENABLED", True)
|
||||
@mock.patch("cms.djangoapps.contentstore.toggles.libraries_v1_enabled", True)
|
||||
def test_library_creator_status_with_is_staff_user_no_org(self):
|
||||
print(self.user.is_staff)
|
||||
self.assertEqual(user_can_create_library(self.user, None), False)
|
||||
|
||||
# When creator groups are enabled, global staff can create libraries in any org
|
||||
@mock.patch("cms.djangoapps.contentstore.views.library.LIBRARIES_ENABLED", True)
|
||||
@mock.patch("cms.djangoapps.contentstore.toggles.libraries_v1_enabled", True)
|
||||
def test_library_creator_status_for_enabled_creator_group_setting_with_is_staff_user(self):
|
||||
with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}):
|
||||
self.assertEqual(user_can_create_library(self.user, 'RandomOrg'), True)
|
||||
|
||||
# When creator groups are enabled, course creators can create libraries in any org.
|
||||
@mock.patch("cms.djangoapps.contentstore.views.library.LIBRARIES_ENABLED", True)
|
||||
@mock.patch("cms.djangoapps.contentstore.toggles.libraries_v1_enabled", True)
|
||||
def test_library_creator_status_with_course_creator_role_for_enabled_creator_group_setting(self):
|
||||
_, nostaff_user = self.create_non_staff_authed_user_client()
|
||||
with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}):
|
||||
@@ -102,7 +102,7 @@ class UnitTestLibraries(CourseTestCase):
|
||||
|
||||
# When creator groups are enabled, course staff members can create libraries
|
||||
# but only in the org they are course staff for.
|
||||
@mock.patch("cms.djangoapps.contentstore.views.library.LIBRARIES_ENABLED", True)
|
||||
@mock.patch("cms.djangoapps.contentstore.toggles.libraries_v1_enabled", True)
|
||||
def test_library_creator_status_with_course_staff_role_for_enabled_creator_group_setting(self):
|
||||
_, nostaff_user = self.create_non_staff_authed_user_client()
|
||||
with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}):
|
||||
@@ -112,7 +112,7 @@ class UnitTestLibraries(CourseTestCase):
|
||||
|
||||
# When creator groups are enabled, course instructor members can create libraries
|
||||
# but only in the org they are course staff for.
|
||||
@mock.patch("cms.djangoapps.contentstore.views.library.LIBRARIES_ENABLED", True)
|
||||
@mock.patch("cms.djangoapps.contentstore.toggles.libraries_v1_enabled", True)
|
||||
def test_library_creator_status_with_course_instructor_role_for_enabled_creator_group_setting(self):
|
||||
_, nostaff_user = self.create_non_staff_authed_user_client()
|
||||
with mock.patch.dict('django.conf.settings.FEATURES', {"ENABLE_CREATOR_GROUP": True}):
|
||||
@@ -134,7 +134,7 @@ class UnitTestLibraries(CourseTestCase):
|
||||
Ensure that the setting DISABLE_LIBRARY_CREATION overrides DISABLE_COURSE_CREATION as expected.
|
||||
"""
|
||||
_, nostaff_user = self.create_non_staff_authed_user_client()
|
||||
with mock.patch("cms.djangoapps.contentstore.views.library.LIBRARIES_ENABLED", True):
|
||||
with mock.patch("cms.djangoapps.contentstore.toggles.libraries_v1_enabled", True):
|
||||
with mock.patch.dict(
|
||||
"django.conf.settings.FEATURES",
|
||||
{
|
||||
@@ -145,7 +145,7 @@ class UnitTestLibraries(CourseTestCase):
|
||||
self.assertEqual(user_can_create_library(nostaff_user, 'SomEOrg'), expected_status)
|
||||
|
||||
@mock.patch.dict('django.conf.settings.FEATURES', {'DISABLE_COURSE_CREATION': True})
|
||||
@mock.patch("cms.djangoapps.contentstore.views.library.LIBRARIES_ENABLED", True)
|
||||
@mock.patch("cms.djangoapps.contentstore.toggles.libraries_v1_enabled", True)
|
||||
def test_library_creator_status_with_no_course_creator_role_and_disabled_nonstaff_course_creation(self):
|
||||
"""
|
||||
Ensure that `DISABLE_COURSE_CREATION` feature works with libraries as well.
|
||||
@@ -161,7 +161,7 @@ class UnitTestLibraries(CourseTestCase):
|
||||
self.assertEqual(get_response.status_code, 200)
|
||||
self.assertEqual(post_response.status_code, 403)
|
||||
|
||||
@patch("cms.djangoapps.contentstore.views.library.LIBRARIES_ENABLED", False)
|
||||
@mock.patch.dict('django.conf.settings.FEATURES', {'ENABLE_CONTENT_LIBRARIES': False})
|
||||
def test_with_libraries_disabled(self):
|
||||
"""
|
||||
The library URLs should return 404 if libraries are disabled.
|
||||
|
||||
@@ -222,7 +222,7 @@ urlpatterns += [
|
||||
path('openassessment/fileupload/', include('openassessment.fileupload.urls')),
|
||||
]
|
||||
|
||||
if settings.FEATURES.get('ENABLE_CONTENT_LIBRARIES'):
|
||||
if toggles.ENABLE_CONTENT_LIBRARIES:
|
||||
urlpatterns += [
|
||||
re_path(fr'^library/{LIBRARY_KEY_PATTERN}?$',
|
||||
contentstore_views.library_handler, name='library_handler'),
|
||||
|
||||
Reference in New Issue
Block a user