Skip to content

Commit

Permalink
refactor: use contentstore.toggles.libraries_v1_enabled()
Browse files Browse the repository at this point in the history
instead of the settings.FEATURES['ENABLE_CONTENT_LIBRARIES'] flag.
This flag 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".
  • Loading branch information
pomegranited committed Oct 17, 2024
1 parent b7e1f90 commit 1b09f94
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 27 deletions.
23 changes: 20 additions & 3 deletions cms/djangoapps/contentstore/toggles.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""
CMS feature toggles.
"""
from django.conf import settings

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
Expand Down Expand Up @@ -600,6 +602,8 @@ def default_enable_flexible_peer_openassessments(course_key):
# .. toggle_implementation: WaffleFlag
# .. toggle_default: False
# .. toggle_description: Hides legacy (v1) Libraries tab in Authoring MFE.
# This toggle interacts with settings.FEATURES['ENABLE_CONTENT_LIBRARIES']: 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
Expand All @@ -612,17 +616,25 @@ def default_enable_flexible_peer_openassessments(course_key):
)


LIBRARIES_ENABLED = settings.FEATURES.get('ENABLE_CONTENT_LIBRARIES', False)


def libraries_v1_enabled():
"""
Returns a boolean if Libraries V2 is enabled in the new Studio Home.
"""
return not DISABLE_LEGACY_LIBRARIES.is_enabled()
return (
LIBRARIES_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 settings.FEATURES['ENABLE_CONTENT_LIBRARIES']: 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
Expand All @@ -638,6 +650,11 @@ def libraries_v1_enabled():
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.
"""
# We use Meilisearch to index Libraries V2 content for display on new Studio Home.
return search_api.is_meilisearch_enabled() and not DISABLE_NEW_LIBRARIES.is_enabled()
return (
LIBRARIES_ENABLED and
search_api.is_meilisearch_enabled() and
not DISABLE_NEW_LIBRARIES.is_enabled()
)
10 changes: 4 additions & 6 deletions cms/djangoapps/contentstore/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1540,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],
}
Expand All @@ -1554,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'),
Expand Down Expand Up @@ -1675,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,
)

Expand All @@ -1691,15 +1689,15 @@ 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 = {
'courses': active_courses,
'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(),
Expand Down
9 changes: 4 additions & 5 deletions cms/djangoapps/contentstore/views/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
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
Expand All @@ -50,13 +51,11 @@

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.
Expand All @@ -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
Expand Down Expand Up @@ -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

Expand Down
24 changes: 12 additions & 12 deletions cms/djangoapps/contentstore/views/tests/test_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,44 +56,44 @@ def setUp(self):
# 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}):
Expand All @@ -102,7 +102,7 @@ def test_library_creator_status_with_course_creator_role_for_enabled_creator_gro

# 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}):
Expand All @@ -112,7 +112,7 @@ def test_library_creator_status_with_course_staff_role_for_enabled_creator_group

# 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}):
Expand All @@ -134,7 +134,7 @@ def test_library_creator_status_settings(self, disable_course, disable_library,
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",
{
Expand All @@ -145,7 +145,7 @@ def test_library_creator_status_settings(self, disable_course, disable_library,
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.
Expand All @@ -161,7 +161,7 @@ def test_library_creator_status_with_no_course_creator_role_and_disabled_nonstaf
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("cms.djangoapps.contentstore.toggles.libraries_v1_enabled", False)
def test_with_libraries_disabled(self):
"""
The library URLs should return 404 if libraries are disabled.
Expand Down
2 changes: 1 addition & 1 deletion cms/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@
path('openassessment/fileupload/', include('openassessment.fileupload.urls')),
]

if settings.FEATURES.get('ENABLE_CONTENT_LIBRARIES'):
if toggles.libraries_v1_enabled():
urlpatterns += [
re_path(fr'^library/{LIBRARY_KEY_PATTERN}?$',
contentstore_views.library_handler, name='library_handler'),
Expand Down

0 comments on commit 1b09f94

Please sign in to comment.