Use SettingDictToggle to document ENTRANCE_EXAMS

This commit is contained in:
Régis Behmo
2020-10-12 23:14:36 +02:00
parent 460f637fa7
commit 87b5463d42
10 changed files with 49 additions and 37 deletions

View File

@@ -58,7 +58,6 @@ from util.course import get_link_for_about_page
from util.date_utils import get_default_time_display
from util.json_request import JsonResponse, JsonResponseBadRequest, expect_json
from util.milestones_helpers import (
is_entrance_exams_enabled,
is_prerequisite_courses_enabled,
is_valid_course_key,
remove_prerequisite_course,
@@ -66,6 +65,7 @@ from util.milestones_helpers import (
)
from util.organizations_helpers import add_organization_course, get_organization_by_short_name, organizations_enabled
from util.string_utils import _has_non_ascii_characters
from openedx.core import toggles as core_toggles
from xblock_django.api import deprecated_xblocks
from xmodule.contentstore.content import StaticContent
from xmodule.course_module import DEFAULT_START_DATE, CourseFields
@@ -1121,7 +1121,7 @@ def settings_handler(request, course_key_string):
'show_min_grade_warning': False,
'enrollment_end_editable': enrollment_end_editable,
'is_prerequisite_courses_enabled': is_prerequisite_courses_enabled(),
'is_entrance_exams_enabled': is_entrance_exams_enabled(),
'is_entrance_exams_enabled': core_toggles.ENTRANCE_EXAMS.is_enabled(),
'enable_extended_course_details': enable_extended_course_details,
'upgrade_deadline': upgrade_deadline,
'course_authoring_microfrontend_url': course_authoring_microfrontend_url,
@@ -1183,7 +1183,7 @@ def settings_handler(request, course_key_string):
# feature-specific settings and handle them accordingly
# We have to be careful that we're only executing the following logic if we actually
# need to create or delete an entrance exam from the specified course
if is_entrance_exams_enabled():
if core_toggles.ENTRANCE_EXAMS.is_enabled():
course_entrance_exam_present = course_module.entrance_exam_enabled
entrance_exam_enabled = request.json.get('entrance_exam_enabled', '') == 'true'
ee_min_score_pct = request.json.get('entrance_exam_minimum_score_pct', None)

View File

@@ -20,6 +20,7 @@ from cms.djangoapps.models.settings.course_metadata import CourseMetadata
from openedx.core.djangolib.js_utils import dump_js_escaped_json
from student.auth import has_course_author_access
from util import milestones_helpers
from openedx.core import toggles as core_toggles
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import ItemNotFoundError
@@ -42,23 +43,21 @@ def _get_default_entrance_exam_minimum_pct():
return entrance_exam_minimum_score_pct
def check_feature_enabled(feature_name):
def check_entrance_exams_enabled(view_func):
"""
Ensure the specified feature is turned on. Return an HTTP 400 code if not.
Ensure the entrance exams feature is turned on. Return an HTTP 400 code if not.
"""
def _check_feature_enabled(view_func):
def _decorator(request, *args, **kwargs):
# Deny access if the entrance exam feature is disabled
if not settings.FEATURES.get(feature_name, False):
return HttpResponseBadRequest()
return view_func(request, *args, **kwargs)
return wraps(view_func)(_decorator)
return _check_feature_enabled
def _decorator(request, *args, **kwargs):
# Deny access if the entrance exam feature is disabled
if not core_toggles.ENTRANCE_EXAMS.is_enabled():
return HttpResponseBadRequest()
return view_func(request, *args, **kwargs)
return wraps(view_func)(_decorator)
@login_required
@ensure_csrf_cookie
@check_feature_enabled(feature_name='ENTRANCE_EXAMS')
@check_entrance_exams_enabled
def entrance_exam(request, course_key_string):
"""
The restful handler for entrance exams.
@@ -105,7 +104,7 @@ def entrance_exam(request, course_key_string):
return HttpResponse(status=405)
@check_feature_enabled(feature_name='ENTRANCE_EXAMS')
@check_entrance_exams_enabled
def create_entrance_exam(request, course_key, entrance_exam_minimum_score_pct):
"""
api method to create an entrance exam.
@@ -186,7 +185,7 @@ def _get_entrance_exam(request, course_key):
return HttpResponse(status=404)
@check_feature_enabled(feature_name='ENTRANCE_EXAMS')
@check_entrance_exams_enabled
def update_entrance_exam(request, course_key, exam_data):
"""
Operation to update course fields pertaining to entrance exams
@@ -200,7 +199,7 @@ def update_entrance_exam(request, course_key, exam_data):
CourseMetadata.update_from_dict(metadata, course, request.user)
@check_feature_enabled(feature_name='ENTRANCE_EXAMS')
@check_entrance_exams_enabled
def delete_entrance_exam(request, course_key):
"""
api method to delete an entrance exam

View File

@@ -14,7 +14,7 @@ from xblock.core import XBlock
from cms.djangoapps.models.settings.course_grading import CourseGradingModel
from edxmako.shortcuts import render_to_string
from util.milestones_helpers import is_entrance_exams_enabled
from openedx.core.toggles import ENTRANCE_EXAMS
from xmodule.modulestore.django import modulestore
from xmodule.tabs import StaticTab
from xmodule.x_module import DEPRECATION_VSCOMPAT_EVENT
@@ -214,7 +214,7 @@ def create_xblock(parent_locator, user, category, display_name, boilerplate=None
# Entrance Exams: Chapter module positioning
child_position = None
if is_entrance_exams_enabled():
if ENTRANCE_EXAMS.is_enabled():
if category == 'chapter' and is_entrance_exam:
fields['is_entrance_exam'] = is_entrance_exam
fields['in_entrance_exam'] = True # Inherited metadata, all children will have it
@@ -238,7 +238,7 @@ def create_xblock(parent_locator, user, category, display_name, boilerplate=None
)
# Entrance Exams: Grader assignment
if is_entrance_exams_enabled():
if ENTRANCE_EXAMS.is_enabled():
course_key = usage_key.course_key
course = store.get_course(course_key)
if hasattr(course, 'entrance_exam_enabled') and course.entrance_exam_enabled:

View File

@@ -43,7 +43,7 @@ from static_replace import replace_static_urls
from student.auth import has_studio_read_access, has_studio_write_access
from util.date_utils import get_default_time_display
from util.json_request import JsonResponse, expect_json
from util.milestones_helpers import is_entrance_exams_enabled
from openedx.core.toggles import ENTRANCE_EXAMS
from xblock_django.user_service import DjangoXBlockUserService
from xmodule.course_module import DEFAULT_START_DATE
from xmodule.library_tools import LibraryToolsService
@@ -100,7 +100,7 @@ def _filter_entrance_exam_grader(graders):
views/controls like the 'Grade as' dropdown that allows a course author to select
the grader type for a given section of a course
"""
if is_entrance_exams_enabled():
if ENTRANCE_EXAMS.is_enabled():
graders = [grader for grader in graders if grader.get('type') != u'Entrance Exam']
return graders

View File

@@ -18,6 +18,8 @@ from cms.djangoapps.contentstore.views.organization import OrganizationListView
from openedx.core.apidocs import api_info
from openedx.core.djangoapps.password_policy import compliance as password_policy_compliance
from openedx.core.djangoapps.password_policy.forms import PasswordPolicyAwareAdminAuthForm
from openedx.core import toggles as core_toggles
django_autodiscover()
admin.site.site_header = _('Studio Administration')
@@ -220,7 +222,7 @@ urlpatterns.append(url(r'^admin/password_change/$', handler404))
urlpatterns.append(url(r'^admin/', admin.site.urls))
# enable entrance exams
if settings.FEATURES.get('ENTRANCE_EXAMS'):
if core_toggles.ENTRANCE_EXAMS.is_enabled():
urlpatterns.append(url(r'^course/{}/entrance_exam/?$'.format(settings.COURSE_KEY_PATTERN),
contentstore_views.entrance_exam))

View File

@@ -76,7 +76,7 @@ from openedx.core.djangoapps.xmodule_django.models import NoneToEmptyManager
from openedx.core.djangolib.model_mixins import DeletableByUserValue
from student.signals import ENROLL_STATUS_CHANGE, ENROLLMENT_TRACK_UPDATED, UNENROLL_DONE
from track import contexts, segment
from util.milestones_helpers import is_entrance_exams_enabled
from openedx.core.toggles import ENTRANCE_EXAMS
from util.model_utils import emit_field_changed_events, get_changed_fields_dict
from util.query import use_read_replica_if_available
@@ -2659,7 +2659,7 @@ class EntranceExamConfiguration(models.Model):
Return True if given user can skip entrance exam for given course otherwise False.
"""
can_skip = False
if is_entrance_exams_enabled():
if ENTRANCE_EXAMS.is_enabled():
try:
record = EntranceExamConfiguration.objects.get(user=user, course_id=course_key)
can_skip = record.skip_entrance_exam

View File

@@ -18,6 +18,7 @@ from openedx.core.djangoapps.content.course_overviews.models import CourseOvervi
from openedx.core.lib.cache_utils import get_cache
from xmodule.modulestore.django import modulestore
NAMESPACE_CHOICES = {
'ENTRANCE_EXAM': 'entrance_exams'
}
@@ -33,7 +34,6 @@ REQUEST_CACHE_NAME = "milestones"
# .. toggle_creation_date: 2014-11-21
# TODO this should be moved to edx/edx-milestones
ENABLE_MILESTONES_APP = SettingDictToggle("FEATURES", "MILESTONES_APP", default=False, module_name=__name__)
ENABLE_ENTRANCE_EXAMS = SettingDictToggle("FEATURES", "ENTRANCE_EXAMS", default=False, module_name=__name__)
def get_namespace_choices():
@@ -43,14 +43,6 @@ def get_namespace_choices():
return NAMESPACE_CHOICES
def is_entrance_exams_enabled():
"""
Checks to see if the Entrance Exams feature is enabled
Use this operation instead of checking the feature flag all over the place
"""
return ENABLE_ENTRANCE_EXAMS.is_enabled()
def is_prerequisite_courses_enabled():
"""
Returns boolean indicating prerequisite courses enabled system wide or not.

View File

@@ -7,7 +7,8 @@ from opaque_keys.edx.keys import UsageKey
from lms.djangoapps.courseware.access import has_access
from student.models import EntranceExamConfiguration
from util.milestones_helpers import get_required_content, is_entrance_exams_enabled
from util.milestones_helpers import get_required_content
from openedx.core.toggles import ENTRANCE_EXAMS
from xmodule.modulestore.django import modulestore
@@ -15,7 +16,7 @@ def course_has_entrance_exam(course):
"""
Checks to see if a course is properly configured for an entrance exam
"""
if not is_entrance_exams_enabled():
if not ENTRANCE_EXAMS.is_enabled():
return False
entrance_exam_enabled = getattr(course, 'entrance_exam_enabled', None)
if not entrance_exam_enabled:

View File

@@ -11,6 +11,7 @@ from opaque_keys.edx.keys import UsageKey
from lms.djangoapps.courseware.entrance_exams import get_entrance_exam_content
from openedx.core.lib.gating import api as gating_api
from util import milestones_helpers
from openedx.core.toggles import ENTRANCE_EXAMS
log = logging.getLogger(__name__)
@@ -48,7 +49,7 @@ def evaluate_entrance_exam(course_grade, user):
fulfilled for the user.
"""
course = course_grade.course_data.course
if milestones_helpers.is_entrance_exams_enabled() and getattr(course, 'entrance_exam_enabled', False):
if ENTRANCE_EXAMS.is_enabled() and getattr(course, 'entrance_exam_enabled', False):
if get_entrance_exam_content(user, course):
exam_chapter_key = get_entrance_exam_usage_key(course)
exam_score_ratio = get_entrance_exam_score_ratio(course_grade, exam_chapter_key)

17
openedx/core/toggles.py Normal file
View File

@@ -0,0 +1,17 @@
"""
Feature toggles used across the platform. Toggles should only be added to this module if we don't have a better place
for them. Generally speaking, they should be added to the most appropriate app or repo.
"""
from edx_toggles.toggles import SettingDictToggle
# .. toggle_name: FEATURES['ENTRANCE_EXAMS']
# .. toggle_implementation: SettingDictToggle
# .. toggle_default: False
# .. toggle_description: Enable entrance exams feature. When enabled, students see an exam xblock as the first unit
# of the course.
# .. toggle_use_cases: open_edx
# .. toggle_creation_date: 2015-12-01
# .. toggle_tickets: https://openedx.atlassian.net/browse/SOL-40
ENTRANCE_EXAMS = SettingDictToggle(
"FEATURES", "ENTRANCE_EXAMS", default=False, module_name=__name__
)