Use SettingDictToggle to document ENTRANCE_EXAMS
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
17
openedx/core/toggles.py
Normal 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__
|
||||
)
|
||||
Reference in New Issue
Block a user