feat: Added Waffle Flags for Courseware Search feature
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -136,6 +136,7 @@ build
|
||||
\#*\#
|
||||
.env/
|
||||
openedx/core/djangoapps/django_comment_common/comment_client/python
|
||||
openedx/core/djangoapps/cache_toolbox/__pycache__
|
||||
autodeploy.properties
|
||||
.ws_migrations_complete
|
||||
dist
|
||||
|
||||
@@ -30,6 +30,7 @@ from opaque_keys.edx.keys import CourseKey, UsageKey
|
||||
from pytz import UTC
|
||||
from openedx.core.djangoapps.waffle_utils.models import WaffleFlagCourseOverrideModel
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APIClient
|
||||
from web_fragments.fragment import Fragment
|
||||
from xblock.core import XBlock
|
||||
from xblock.fields import Scope, String
|
||||
@@ -76,7 +77,10 @@ from lms.djangoapps.courseware.block_render import get_block, handle_xblock_call
|
||||
from lms.djangoapps.courseware.tests.factories import StudentModuleFactory
|
||||
from lms.djangoapps.courseware.tests.helpers import MasqueradeMixin, get_expiration_banner_text, set_preview_mode
|
||||
from lms.djangoapps.courseware.testutils import RenderXBlockTestMixin
|
||||
from lms.djangoapps.courseware.toggles import COURSEWARE_OPTIMIZED_RENDER_XBLOCK
|
||||
from lms.djangoapps.courseware.toggles import (
|
||||
COURSEWARE_MICROFRONTEND_SEARCH_ENABLED,
|
||||
COURSEWARE_OPTIMIZED_RENDER_XBLOCK,
|
||||
)
|
||||
from lms.djangoapps.courseware.user_state_client import DjangoXBlockUserStateClient
|
||||
from lms.djangoapps.courseware.views.views import (
|
||||
BasePublicVideoXBlockView,
|
||||
@@ -3683,3 +3687,41 @@ class TestPublicVideoXBlockEmbedView(TestBasePublicVideoXBlock):
|
||||
assert template == 'public_video_share_embed.html'
|
||||
assert context['fragment'] == fragment
|
||||
assert context['course'] == self.course
|
||||
|
||||
|
||||
class TestCoursewareMFESearchAPI(SharedModuleStoreTestCase):
|
||||
"""
|
||||
Tests the endpoint to fetch the Courseware Search waffle flag enabled status.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.course = CourseFactory.create()
|
||||
|
||||
self.client = APIClient()
|
||||
self.apiUrl = reverse('courseware_search_enabled_view', kwargs={'course_id': str(self.course.id)})
|
||||
|
||||
@override_waffle_flag(COURSEWARE_MICROFRONTEND_SEARCH_ENABLED, active=True)
|
||||
def test_courseware_mfe_search_enabled(self):
|
||||
"""
|
||||
Getter to check if user is allowed to use Courseware Search.
|
||||
"""
|
||||
|
||||
response = self.client.get(self.apiUrl, content_type='application/json')
|
||||
body = json.loads(response.content.decode('utf-8'))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(body, {'enabled': True})
|
||||
|
||||
@override_waffle_flag(COURSEWARE_MICROFRONTEND_SEARCH_ENABLED, active=False)
|
||||
def test_is_mfe_search_disabled(self):
|
||||
"""
|
||||
Getter to check if user is allowed to use Courseware Search.
|
||||
"""
|
||||
|
||||
response = self.client.get(self.apiUrl, content_type='application/json')
|
||||
body = json.loads(response.content.decode('utf-8'))
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(body, {'enabled': False})
|
||||
|
||||
@@ -55,6 +55,19 @@ COURSEWARE_MICROFRONTEND_PROGRESS_MILESTONES_STREAK_CELEBRATION = CourseWaffleFl
|
||||
f'{WAFFLE_FLAG_NAMESPACE}.mfe_progress_milestones_streak_celebration', __name__
|
||||
)
|
||||
|
||||
# .. toggle_name: courseware.mfe_courseware_search
|
||||
# .. toggle_implementation: WaffleFlag
|
||||
# .. toggle_default: False
|
||||
# .. toggle_description: Enables Courseware Search on Learning MFE
|
||||
# .. toggle_use_cases: temporary
|
||||
# .. toggle_creation_date: 2023-09-28
|
||||
# .. toggle_target_removal_date: None
|
||||
# .. toggle_tickets: KBK-20
|
||||
# .. toggle_warning: None.
|
||||
COURSEWARE_MICROFRONTEND_SEARCH_ENABLED = CourseWaffleFlag(
|
||||
f'{WAFFLE_FLAG_NAMESPACE}.mfe_courseware_search', __name__
|
||||
)
|
||||
|
||||
# .. toggle_name: courseware.mfe_progress_milestones_streak_discount_enabled
|
||||
# .. toggle_implementation: CourseWaffleFlag
|
||||
# .. toggle_default: False
|
||||
@@ -153,3 +166,10 @@ def course_is_invitation_only(courselike) -> bool:
|
||||
|
||||
def learning_assistant_is_active(course_key):
|
||||
return COURSEWARE_LEARNING_ASSISTANT.is_enabled(course_key)
|
||||
|
||||
|
||||
def courseware_mfe_search_is_enabled(course_key=None):
|
||||
"""
|
||||
Return whether the courseware.mfe_courseware_search flag is on.
|
||||
"""
|
||||
return COURSEWARE_MICROFRONTEND_SEARCH_ENABLED.is_enabled(course_key)
|
||||
|
||||
@@ -18,8 +18,8 @@ from django.contrib.auth.models import AnonymousUser, User # lint-amnesty, pyli
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db import transaction
|
||||
from django.db.models import Q, prefetch_related_objects
|
||||
from django.http import Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
|
||||
from django.shortcuts import redirect
|
||||
from django.http import JsonResponse, Http404, HttpResponse, HttpResponseBadRequest, HttpResponseForbidden
|
||||
from django.template.context_processors import csrf
|
||||
from django.urls import reverse
|
||||
from django.utils.decorators import method_decorator
|
||||
@@ -38,8 +38,8 @@ from markupsafe import escape
|
||||
from opaque_keys import InvalidKeyError
|
||||
from opaque_keys.edx.keys import CourseKey, UsageKey
|
||||
from openedx_filters.learning.filters import CourseAboutRenderStarted
|
||||
from pytz import UTC
|
||||
from requests.exceptions import ConnectionError, Timeout # pylint: disable=redefined-builtin
|
||||
from pytz import UTC
|
||||
from rest_framework import status
|
||||
from rest_framework.decorators import api_view, throttle_classes
|
||||
from rest_framework.response import Response
|
||||
@@ -87,7 +87,7 @@ from lms.djangoapps.courseware.masquerade import is_masquerading_as_specific_stu
|
||||
from lms.djangoapps.courseware.model_data import FieldDataCache
|
||||
from lms.djangoapps.courseware.models import BaseStudentModuleHistory, StudentModule
|
||||
from lms.djangoapps.courseware.permissions import MASQUERADE_AS_STUDENT, VIEW_COURSE_HOME, VIEW_COURSEWARE
|
||||
from lms.djangoapps.courseware.toggles import course_is_invitation_only
|
||||
from lms.djangoapps.courseware.toggles import course_is_invitation_only, courseware_mfe_search_is_enabled
|
||||
from lms.djangoapps.courseware.user_state_client import DjangoXBlockUserStateClient
|
||||
from lms.djangoapps.courseware.utils import (
|
||||
_use_new_financial_assistance_flow,
|
||||
@@ -2275,3 +2275,15 @@ def get_learner_username(learner_identifier):
|
||||
learner = User.objects.filter(Q(username=learner_identifier) | Q(email=learner_identifier)).first()
|
||||
if learner:
|
||||
return learner.username
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
def courseware_mfe_search_enabled(request, course_id=None):
|
||||
"""
|
||||
Simple GET endpoint to expose whether the course may use Courseware Search.
|
||||
"""
|
||||
|
||||
course_key = CourseKey.from_string(course_id) if course_id else None
|
||||
|
||||
payload = {"enabled": courseware_mfe_search_is_enabled(course_key)}
|
||||
return JsonResponse(payload)
|
||||
|
||||
10
lms/urls.py
10
lms/urls.py
@@ -752,6 +752,16 @@ urlpatterns += [
|
||||
),
|
||||
]
|
||||
|
||||
urlpatterns += [
|
||||
re_path(
|
||||
r'^courses/{}/courseware-search/enabled/$'.format(
|
||||
settings.COURSE_ID_PATTERN,
|
||||
),
|
||||
courseware_views.courseware_mfe_search_enabled,
|
||||
name='courseware_search_enabled_view',
|
||||
),
|
||||
]
|
||||
|
||||
urlpatterns += [
|
||||
re_path(
|
||||
r'^courses/{}/lti_tab/(?P<provider_uuid>[^/]+)/$'.format(
|
||||
|
||||
Reference in New Issue
Block a user