refactor!: switch from LegacyWaffle* to modern waffles (#30330)
This is a first stage for removing the LegacyWaffle* classes. LegacyWaffleFlag usage replaced with WaffleFlag; LegacyWaffleSwitche usage replaced with WaffleSwitch; New CourseWaffleFlag added to the temporary module __future__ as FutureCourseWaffleFlag; Updated all the imports to use CourseWaffleFlag from the __future__ module; BREAKING CHANGE: A number of toggle related constants (e.g. ENABLE_ACCESSIBILITY_POLICY_PAGE) changed types. They were strings, and are now toggle instances (e.g. WaffleSwitch). Although the entire refactor should be self-contained in edx-platform, if any plugins or dependencies were directly using these constants, they will break. If this is the case, try to find a better publicized way of exposing those toggles.
This commit is contained in:
@@ -1,12 +1,10 @@
|
||||
"""
|
||||
Toggles for course apps.
|
||||
"""
|
||||
from edx_toggles.toggles import LegacyWaffleSwitchNamespace
|
||||
|
||||
from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag
|
||||
from openedx.core.djangoapps.waffle_utils.__future__ import FutureCourseWaffleFlag as CourseWaffleFlag
|
||||
|
||||
#: Namespace for use by course apps for creating availability toggles
|
||||
COURSE_APPS_WAFFLE_NAMESPACE = LegacyWaffleSwitchNamespace("course_apps")
|
||||
COURSE_APPS_WAFFLE_NAMESPACE = 'course_apps'
|
||||
|
||||
# .. toggle_name: course_apps.proctoring_settings_modal_view
|
||||
# .. toggle_use_cases: temporary
|
||||
@@ -18,7 +16,7 @@ COURSE_APPS_WAFFLE_NAMESPACE = LegacyWaffleSwitchNamespace("course_apps")
|
||||
# .. toggle_creation_date: 2021-08-17
|
||||
# .. toggle_target_removal_date: None
|
||||
PROCTORING_SETTINGS_MODAL_VIEW = CourseWaffleFlag(
|
||||
COURSE_APPS_WAFFLE_NAMESPACE, 'proctoring_settings_modal_view', module_name=__name__,
|
||||
f'{COURSE_APPS_WAFFLE_NAMESPACE}.proctoring_settings_modal_view', __name__
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -3,11 +3,9 @@ This module contains various configuration settings via
|
||||
waffle switches for the live app.
|
||||
"""
|
||||
|
||||
from edx_toggles.toggles import LegacyWaffleFlagNamespace
|
||||
from openedx.core.djangoapps.waffle_utils.__future__ import FutureCourseWaffleFlag as CourseWaffleFlag
|
||||
|
||||
from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag
|
||||
|
||||
WAFFLE_NAMESPACE = LegacyWaffleFlagNamespace(name='course_live')
|
||||
WAFFLE_NAMESPACE = 'course_live'
|
||||
|
||||
# .. toggle_name: course_live.enable_course_live
|
||||
# .. toggle_implementation: CourseWaffleFlag
|
||||
@@ -18,8 +16,4 @@ WAFFLE_NAMESPACE = LegacyWaffleFlagNamespace(name='course_live')
|
||||
# .. toggle_target_removal_date: 2022-06-02
|
||||
# .. toggle_warnings: When the flag is ON, the course live app will be visible in the course authoring mfe
|
||||
# .. toggle_tickets: TNL-9603
|
||||
ENABLE_COURSE_LIVE = CourseWaffleFlag(
|
||||
waffle_namespace=WAFFLE_NAMESPACE,
|
||||
flag_name='enable_course_live',
|
||||
module_name=__name__,
|
||||
)
|
||||
ENABLE_COURSE_LIVE = CourseWaffleFlag(f'{WAFFLE_NAMESPACE}.enable_course_live', __name__)
|
||||
|
||||
@@ -3,12 +3,10 @@ This module contains various configuration settings via
|
||||
waffle switches for the discussions app.
|
||||
"""
|
||||
|
||||
from edx_toggles.toggles import LegacyWaffleFlagNamespace
|
||||
|
||||
from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag
|
||||
from openedx.core.djangoapps.waffle_utils.__future__ import FutureCourseWaffleFlag as CourseWaffleFlag
|
||||
|
||||
|
||||
WAFFLE_NAMESPACE = LegacyWaffleFlagNamespace(name='discussions')
|
||||
WAFFLE_NAMESPACE = 'discussions'
|
||||
|
||||
# .. toggle_name: discussions.override_discussion_legacy_settings
|
||||
# .. toggle_implementation: CourseWaffleFlag
|
||||
@@ -20,9 +18,7 @@ WAFFLE_NAMESPACE = LegacyWaffleFlagNamespace(name='discussions')
|
||||
# .. toggle_warnings: When the flag is ON, the discussion settings will be available on legacy experience.
|
||||
# .. toggle_tickets: TNL-8389
|
||||
OVERRIDE_DISCUSSION_LEGACY_SETTINGS_FLAG = CourseWaffleFlag(
|
||||
waffle_namespace=WAFFLE_NAMESPACE,
|
||||
flag_name='override_discussion_legacy_settings',
|
||||
module_name=__name__,
|
||||
f'{WAFFLE_NAMESPACE}.override_discussion_legacy_settings', __name__
|
||||
)
|
||||
|
||||
|
||||
@@ -36,7 +32,5 @@ OVERRIDE_DISCUSSION_LEGACY_SETTINGS_FLAG = CourseWaffleFlag(
|
||||
# .. toggle_warnings: When the flag is ON, the new experience for Pages and Resources will be enabled.
|
||||
# .. toggle_tickets: TNL-7791
|
||||
ENABLE_PAGES_AND_RESOURCES_MICROFRONTEND = CourseWaffleFlag(
|
||||
waffle_namespace=WAFFLE_NAMESPACE,
|
||||
flag_name='pages_and_resources_mfe',
|
||||
module_name=__name__,
|
||||
f'{WAFFLE_NAMESPACE}.pages_and_resources_mfe', __name__
|
||||
)
|
||||
|
||||
@@ -8,15 +8,14 @@ if and only if the service is deployed in the Open edX installation.
|
||||
To ensure maximum separation of concerns, and a minimum of interdependencies,
|
||||
this package should be kept small, thin, and stateless.
|
||||
"""
|
||||
from edx_toggles.toggles import WaffleSwitch
|
||||
|
||||
default_app_config = 'openedx.core.djangoapps.programs.apps.ProgramsConfig'
|
||||
|
||||
from edx_toggles.toggles import LegacyWaffleSwitch, LegacyWaffleSwitchNamespace # lint-amnesty, pylint: disable=wrong-import-position
|
||||
|
||||
PROGRAMS_WAFFLE_SWITCH_NAMESPACE = LegacyWaffleSwitchNamespace(name='programs')
|
||||
PROGRAMS_WAFFLE_SWITCH_NAMESPACE = 'programs'
|
||||
|
||||
# This is meant to be enabled until https://openedx.atlassian.net/browse/LEARNER-5573 needs to be resolved
|
||||
ALWAYS_CALCULATE_PROGRAM_PRICE_AS_ANONYMOUS_USER = LegacyWaffleSwitch( # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
PROGRAMS_WAFFLE_SWITCH_NAMESPACE,
|
||||
'always_calculate_program_price_as_anonymous_user',
|
||||
ALWAYS_CALCULATE_PROGRAM_PRICE_AS_ANONYMOUS_USER = WaffleSwitch( # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
f'{PROGRAMS_WAFFLE_SWITCH_NAMESPACE}.always_calculate_program_price_as_anonymous_user',
|
||||
__name__
|
||||
)
|
||||
|
||||
@@ -3,13 +3,12 @@ Contains configuration for schedules app
|
||||
"""
|
||||
|
||||
from crum import get_current_request
|
||||
from edx_toggles.toggles import LegacyWaffleSwitch, LegacyWaffleFlagNamespace, LegacyWaffleSwitchNamespace, WaffleFlag
|
||||
from edx_toggles.toggles import WaffleFlag, WaffleSwitch
|
||||
|
||||
from lms.djangoapps.experiments.flags import ExperimentWaffleFlag
|
||||
from lms.djangoapps.experiments.models import ExperimentData
|
||||
|
||||
WAFFLE_FLAG_NAMESPACE = LegacyWaffleFlagNamespace(name='schedules')
|
||||
WAFFLE_SWITCH_NAMESPACE = LegacyWaffleSwitchNamespace(name='schedules')
|
||||
WAFFLE_NAMESPACE = 'schedules'
|
||||
|
||||
# .. toggle_name: schedules.enable_debugging
|
||||
# .. toggle_implementation: WaffleFlag
|
||||
@@ -17,12 +16,10 @@ WAFFLE_SWITCH_NAMESPACE = LegacyWaffleSwitchNamespace(name='schedules')
|
||||
# .. toggle_description: Enable debug level of logging for schedules messages.
|
||||
# .. toggle_use_cases: open_edx
|
||||
# .. toggle_creation_date: 2017-09-17
|
||||
DEBUG_MESSAGE_WAFFLE_FLAG = WaffleFlag('schedules.enable_debugging', __name__)
|
||||
DEBUG_MESSAGE_WAFFLE_FLAG = WaffleFlag(f'{WAFFLE_NAMESPACE}.enable_debugging', __name__)
|
||||
|
||||
COURSE_UPDATE_SHOW_UNSUBSCRIBE_WAFFLE_SWITCH = LegacyWaffleSwitch( # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
WAFFLE_SWITCH_NAMESPACE,
|
||||
'course_update_show_unsubscribe',
|
||||
__name__
|
||||
COURSE_UPDATE_SHOW_UNSUBSCRIBE_WAFFLE_SWITCH = WaffleSwitch( # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
f'{WAFFLE_NAMESPACE}.course_update_show_unsubscribe', __name__
|
||||
)
|
||||
|
||||
# This experiment waffle is supporting an A/B test we are running on sending course updates from an external service,
|
||||
@@ -31,9 +28,11 @@ COURSE_UPDATE_SHOW_UNSUBSCRIBE_WAFFLE_SWITCH = LegacyWaffleSwitch( # lint-amnes
|
||||
# methods below. We save this flag decision at enrollment time and don't change it even if the flag changes. So you
|
||||
# can't just directly look at flag result.
|
||||
_EXTERNAL_COURSE_UPDATES_EXPERIMENT_ID = 18
|
||||
_EXTERNAL_COURSE_UPDATES_FLAG = ExperimentWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'external_updates', __name__, # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
experiment_id=_EXTERNAL_COURSE_UPDATES_EXPERIMENT_ID,
|
||||
use_course_aware_bucketing=False)
|
||||
_EXTERNAL_COURSE_UPDATES_FLAG = ExperimentWaffleFlag( # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
f'{WAFFLE_NAMESPACE}.external_updates', __name__,
|
||||
experiment_id=_EXTERNAL_COURSE_UPDATES_EXPERIMENT_ID,
|
||||
use_course_aware_bucketing=False
|
||||
)
|
||||
|
||||
|
||||
def set_up_external_updates_for_enrollment(user, course_key):
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
Toggles for accounts related code.
|
||||
"""
|
||||
|
||||
from edx_toggles.toggles import LegacyWaffleFlag
|
||||
from edx_toggles.toggles import WaffleFlag
|
||||
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
|
||||
# .. toggle_name: order_history.redirect_to_microfrontend
|
||||
@@ -15,7 +16,7 @@ from openedx.core.djangoapps.site_configuration import helpers as configuration_
|
||||
# .. toggle_warnings: Also set settings.ORDER_HISTORY_MICROFRONTEND_URL and site's
|
||||
# ENABLE_ORDER_HISTORY_MICROFRONTEND.
|
||||
# .. toggle_tickets: DEPR-17
|
||||
REDIRECT_TO_ORDER_HISTORY_MICROFRONTEND = LegacyWaffleFlag('order_history', 'redirect_to_microfrontend', __name__)
|
||||
REDIRECT_TO_ORDER_HISTORY_MICROFRONTEND = WaffleFlag('order_history.redirect_to_microfrontend', __name__)
|
||||
|
||||
|
||||
def should_redirect_to_order_history_microfrontend():
|
||||
@@ -35,7 +36,7 @@ def should_redirect_to_order_history_microfrontend():
|
||||
# .. toggle_target_removal_date: 2021-12-31
|
||||
# .. toggle_warnings: Also set settings.ACCOUNT_MICROFRONTEND_URL.
|
||||
# .. toggle_tickets: DEPR-17
|
||||
REDIRECT_TO_ACCOUNT_MICROFRONTEND = LegacyWaffleFlag('account', 'redirect_to_microfrontend', __name__)
|
||||
REDIRECT_TO_ACCOUNT_MICROFRONTEND = WaffleFlag('account.redirect_to_microfrontend', __name__)
|
||||
|
||||
|
||||
def should_redirect_to_account_microfrontend():
|
||||
|
||||
@@ -3,10 +3,9 @@ Waffle flags and switches for user authn.
|
||||
"""
|
||||
|
||||
|
||||
from edx_toggles.toggles import LegacyWaffleSwitch, LegacyWaffleSwitchNamespace
|
||||
from edx_toggles.toggles import WaffleSwitch
|
||||
|
||||
_WAFFLE_NAMESPACE = 'user_authn'
|
||||
_WAFFLE_SWITCH_NAMESPACE = LegacyWaffleSwitchNamespace(name=_WAFFLE_NAMESPACE, log_prefix='UserAuthN: ')
|
||||
|
||||
# .. toggle_name: user_authn.enable_login_using_thirdparty_auth_only
|
||||
# .. toggle_implementation: WaffleSwitch
|
||||
@@ -18,10 +17,8 @@ _WAFFLE_SWITCH_NAMESPACE = LegacyWaffleSwitchNamespace(name=_WAFFLE_NAMESPACE, l
|
||||
# .. toggle_target_removal_date: 2020-01-31
|
||||
# .. toggle_warnings: Requires THIRD_PARTY_AUTH_ONLY_DOMAIN to also be set.
|
||||
# .. toggle_tickets: ENT-2461
|
||||
ENABLE_LOGIN_USING_THIRDPARTY_AUTH_ONLY = LegacyWaffleSwitch(
|
||||
_WAFFLE_SWITCH_NAMESPACE,
|
||||
'enable_login_using_thirdparty_auth_only',
|
||||
__name__
|
||||
ENABLE_LOGIN_USING_THIRDPARTY_AUTH_ONLY = WaffleSwitch(
|
||||
f'{_WAFFLE_NAMESPACE}.enable_login_using_thirdparty_auth_only', __name__
|
||||
)
|
||||
|
||||
# .. toggle_name: user_authn.enable_pwned_password_api
|
||||
@@ -32,8 +29,6 @@ ENABLE_LOGIN_USING_THIRDPARTY_AUTH_ONLY = LegacyWaffleSwitch(
|
||||
# .. toggle_creation_date: 2021-09-22
|
||||
# .. toggle_target_removal_date: 2021-12-31
|
||||
# .. toggle_tickets: VAN-664
|
||||
ENABLE_PWNED_PASSWORD_API = LegacyWaffleSwitch(
|
||||
_WAFFLE_SWITCH_NAMESPACE,
|
||||
'enable_pwned_password_api',
|
||||
__name__
|
||||
ENABLE_PWNED_PASSWORD_API = WaffleSwitch(
|
||||
f'{_WAFFLE_NAMESPACE}.enable_pwned_password_api', __name__
|
||||
)
|
||||
|
||||
@@ -22,7 +22,7 @@ from django.utils.translation import gettext as _
|
||||
from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
|
||||
from django.views.decorators.debug import sensitive_post_parameters
|
||||
from edx_django_utils.monitoring import set_custom_attribute
|
||||
from edx_toggles.toggles import LegacyWaffleFlag, LegacyWaffleFlagNamespace
|
||||
from edx_toggles.toggles import WaffleFlag
|
||||
from openedx_events.learning.data import UserData, UserPersonalData
|
||||
from openedx_events.learning.signals import STUDENT_REGISTRATION_COMPLETED
|
||||
from openedx_filters.learning.filters import StudentRegistrationRequested
|
||||
@@ -115,11 +115,7 @@ REGISTER_USER = Signal()
|
||||
# .. toggle_creation_date: 2020-04-30
|
||||
# .. toggle_target_removal_date: 2020-06-01
|
||||
# .. toggle_warnings: This temporary feature toggle does not have a target removal date.
|
||||
REGISTRATION_FAILURE_LOGGING_FLAG = LegacyWaffleFlag(
|
||||
waffle_namespace=LegacyWaffleFlagNamespace(name='registration'),
|
||||
flag_name='enable_failure_logging',
|
||||
module_name=__name__,
|
||||
)
|
||||
REGISTRATION_FAILURE_LOGGING_FLAG = WaffleFlag('registration.enable_failure_logging', __name__)
|
||||
REAL_IP_KEY = 'openedx.core.djangoapps.util.ratelimit.real_ip'
|
||||
|
||||
|
||||
|
||||
@@ -3,11 +3,13 @@ This module contains configuration settings via waffle flags
|
||||
for the Video Pipeline app.
|
||||
"""
|
||||
|
||||
from edx_toggles.toggles import LegacyWaffleFlag, LegacyWaffleFlagNamespace
|
||||
from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag
|
||||
from edx_toggles.toggles import WaffleFlag
|
||||
|
||||
from openedx.core.djangoapps.waffle_utils.__future__ import FutureCourseWaffleFlag as CourseWaffleFlag
|
||||
|
||||
# Videos Namespace
|
||||
WAFFLE_NAMESPACE = 'videos'
|
||||
LOG_PREFIX = 'Videos: '
|
||||
|
||||
# .. toggle_name: videos.deprecate_youtube
|
||||
# .. toggle_implementation: CourseWaffleFlag
|
||||
@@ -17,8 +19,8 @@ WAFFLE_NAMESPACE = 'videos'
|
||||
# .. toggle_use_cases: open_edx
|
||||
# .. toggle_creation_date: 2018-08-03
|
||||
# .. toggle_tickets: https://github.com/edx/edx-platform/pull/18765
|
||||
# TODO: Replace with CourseWaffleFlag() from waffle_flags().
|
||||
DEPRECATE_YOUTUBE = 'deprecate_youtube'
|
||||
DEPRECATE_YOUTUBE = CourseWaffleFlag(f'{WAFFLE_NAMESPACE}.deprecate_youtube', __name__, LOG_PREFIX)
|
||||
|
||||
# .. toggle_name: videos.enable_devstack_video_uploads
|
||||
# .. toggle_implementation: WaffleFlag
|
||||
# .. toggle_default: False
|
||||
@@ -30,34 +32,8 @@ DEPRECATE_YOUTUBE = 'deprecate_youtube'
|
||||
# .. toggle_warnings: Enabling this feature requires that the ROLE_ARN, MFA_SERIAL_NUMBER, MFA_TOKEN settings are
|
||||
# properly defined.
|
||||
# .. toggle_tickets: https://github.com/edx/edx-platform/pull/23375
|
||||
# TODO: Replace with WaffleFlag() from waffle_flags().
|
||||
ENABLE_DEVSTACK_VIDEO_UPLOADS = 'enable_devstack_video_uploads'
|
||||
# TODO: Replace with CourseWaffleFlag() from waffle_flags().
|
||||
ENABLE_VEM_PIPELINE = 'enable_vem_pipeline'
|
||||
ENABLE_DEVSTACK_VIDEO_UPLOADS = WaffleFlag(f'{WAFFLE_NAMESPACE}.enable_devstack_video_uploads', __name__, LOG_PREFIX)
|
||||
|
||||
|
||||
def waffle_flags():
|
||||
"""
|
||||
Returns the namespaced, cached, audited Waffle flags dictionary for Videos.
|
||||
|
||||
IMPORTANT: Do NOT copy this dict pattern and do NOT add new flags to this dict.
|
||||
Instead, replace the string constants above with the actual flag instances.
|
||||
"""
|
||||
namespace = LegacyWaffleFlagNamespace(name=WAFFLE_NAMESPACE, log_prefix='Videos: ')
|
||||
return {
|
||||
DEPRECATE_YOUTUBE: CourseWaffleFlag(
|
||||
waffle_namespace=namespace,
|
||||
flag_name=DEPRECATE_YOUTUBE,
|
||||
module_name=__name__,
|
||||
),
|
||||
ENABLE_DEVSTACK_VIDEO_UPLOADS: LegacyWaffleFlag(
|
||||
waffle_namespace=namespace,
|
||||
flag_name=ENABLE_DEVSTACK_VIDEO_UPLOADS,
|
||||
module_name=__name__,
|
||||
),
|
||||
ENABLE_VEM_PIPELINE: CourseWaffleFlag( # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
waffle_namespace=namespace,
|
||||
flag_name=ENABLE_VEM_PIPELINE,
|
||||
module_name=__name__,
|
||||
)
|
||||
}
|
||||
ENABLE_VEM_PIPELINE = CourseWaffleFlag( # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
f'{WAFFLE_NAMESPACE}.enable_vem_pipeline', __name__, LOG_PREFIX
|
||||
)
|
||||
|
||||
116
openedx/core/djangoapps/waffle_utils/__future__.py
Normal file
116
openedx/core/djangoapps/waffle_utils/__future__.py
Normal file
@@ -0,0 +1,116 @@
|
||||
"""
|
||||
Temporary module to switch from the LegacyWaffle* classes.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from edx_toggles.toggles import WaffleFlag
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FutureCourseWaffleFlag(WaffleFlag):
|
||||
"""
|
||||
Represents a single waffle flag that can be forced on/off for a course. This class should be used instead of
|
||||
WaffleFlag when in the context of a course. This class will also respect any org-level overrides, though
|
||||
course-level overrides will take precedence.
|
||||
|
||||
Uses a cached waffle namespace.
|
||||
|
||||
Usage:
|
||||
|
||||
SOME_COURSE_FLAG = CourseWaffleFlag('my_namespace.some_course_feature', __name__, log_prefix='')
|
||||
|
||||
And then we can check this flag in code with::
|
||||
|
||||
SOME_COURSE_FLAG.is_enabled(course_key)
|
||||
|
||||
To configure a course-level override, go to Django Admin "waffle_utils" -> "Waffle flag course overrides".
|
||||
|
||||
Waffle flag: Set this to the flag name (e.g. my_namespace.some_course_feature).
|
||||
Course id: Set this to the course id (e.g. course-v1:edx+100+Demo)
|
||||
Override choice: (Force on/Force off). "Force on" will enable the waffle flag for all users in a course,
|
||||
overriding any behavior configured on the waffle flag itself. "Force off" will disable the waffle flag
|
||||
for all users in a course, overriding any behavior configured on the waffle flag itself. Requires
|
||||
"Enabled" (see below) to apply.
|
||||
Enabled: Must be marked as "enabled" in order for the override to be applied. These settings can't be
|
||||
deleted, so instead, you need to add another disabled override entry to disable the override.
|
||||
|
||||
To configure an org-level override, go to Django Admin "waffle_utils" -> "Waffle flag org overrides".
|
||||
|
||||
Waffle flag: Set this to the flag name (e.g. my_namespace.some_course_feature).
|
||||
Org name: Set this to the organization name (e.g. edx)
|
||||
Override choice: (Force on/Force off). "Force on" will enable the waffle flag for all users in an org's courses,
|
||||
overriding any behavior configured on the waffle flag itself. "Force off" will disable the waffle flag
|
||||
for all users in a org's courses, overriding any behavior configured on the waffle flag itself. Requires
|
||||
"Enabled" (see below) to apply.
|
||||
Enabled: Must be marked as "enabled" in order for the override to be applied. These settings can't be
|
||||
deleted, so instead, you need to add another disabled override entry to disable the override.
|
||||
|
||||
"""
|
||||
|
||||
def _get_course_override_value(self, course_key):
|
||||
"""
|
||||
Returns True/False if the flag was forced on or off for the provided course. Returns None if the flag was not
|
||||
overridden.
|
||||
|
||||
Note: Has side effect of caching the override value.
|
||||
|
||||
Arguments:
|
||||
course_key (CourseKey): The course to check for override before checking waffle.
|
||||
"""
|
||||
# Import is placed here to avoid model import at project startup.
|
||||
from .models import WaffleFlagCourseOverrideModel, WaffleFlagOrgOverrideModel
|
||||
|
||||
course_cache_key = f"{self.name}.cwaffle.{str(course_key)}"
|
||||
course_override = self.cached_flags().get(course_cache_key)
|
||||
|
||||
if course_override is None:
|
||||
course_override = WaffleFlagCourseOverrideModel.override_value(
|
||||
self.name, course_key
|
||||
)
|
||||
self.cached_flags()[course_cache_key] = course_override
|
||||
|
||||
if course_override == WaffleFlagCourseOverrideModel.ALL_CHOICES.on:
|
||||
return True
|
||||
if course_override == WaffleFlagCourseOverrideModel.ALL_CHOICES.off:
|
||||
return False
|
||||
|
||||
# Since no course-specific override was found, fall back to checking at the org-level.
|
||||
if course_key:
|
||||
org = course_key.org
|
||||
org_cache_key = f"{self.name}.owaffle.{org}"
|
||||
org_override = self.cached_flags().get(org_cache_key)
|
||||
|
||||
if org_override is None:
|
||||
org_override = WaffleFlagOrgOverrideModel.override_value(
|
||||
self.name, org
|
||||
)
|
||||
self.cached_flags()[org_cache_key] = org_override
|
||||
|
||||
if org_override == WaffleFlagOrgOverrideModel.ALL_CHOICES.on:
|
||||
return True
|
||||
if org_override == WaffleFlagOrgOverrideModel.ALL_CHOICES.off:
|
||||
return False
|
||||
|
||||
return None
|
||||
|
||||
def is_enabled(self, course_key=None): # pylint: disable=arguments-differ
|
||||
"""
|
||||
Returns whether or not the flag is enabled within the context of a given course.
|
||||
|
||||
Arguments:
|
||||
course_key (Optional[CourseKey]): The course to check for override before
|
||||
checking waffle. If omitted, check whether the flag is enabled
|
||||
outside the context of any course.
|
||||
"""
|
||||
if course_key:
|
||||
assert isinstance(
|
||||
course_key, CourseKey
|
||||
), "Provided course_key '{}' is not instance of CourseKey.".format(
|
||||
course_key
|
||||
)
|
||||
is_enabled_for_course = self._get_course_override_value(course_key)
|
||||
if is_enabled_for_course is not None:
|
||||
return is_enabled_for_course
|
||||
return super().is_enabled()
|
||||
@@ -3,123 +3,30 @@ Extra utilities for waffle: most classes are defined in edx_toggles.toggles (htt
|
||||
we keep here some extra classes for usage within edx-platform. These classes cover course override use cases.
|
||||
"""
|
||||
import logging
|
||||
import warnings
|
||||
from contextlib import contextmanager
|
||||
|
||||
from edx_django_utils.monitoring import set_custom_attribute
|
||||
from edx_toggles.toggles import (
|
||||
LegacyWaffleFlag,
|
||||
LegacyWaffleFlagNamespace,
|
||||
LegacyWaffleSwitch,
|
||||
LegacyWaffleSwitchNamespace,
|
||||
)
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from openedx.core.djangoapps.waffle_utils.__future__ import FutureCourseWaffleFlag
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class CourseWaffleFlag(LegacyWaffleFlag):
|
||||
class CourseWaffleFlag(FutureCourseWaffleFlag):
|
||||
"""
|
||||
Represents a single waffle flag that can be forced on/off for a course. This class should be used instead of
|
||||
WaffleFlag when in the context of a course. This class will also respect any org-level overrides, though
|
||||
course-level overrides will take precedence.
|
||||
|
||||
Uses a cached waffle namespace.
|
||||
|
||||
Usage:
|
||||
|
||||
SOME_COURSE_FLAG = CourseWaffleFlag('my_namespace', 'some_course_feature', __name__)
|
||||
|
||||
And then we can check this flag in code with::
|
||||
|
||||
SOME_COURSE_FLAG.is_enabled(course_key)
|
||||
|
||||
To configure a course-level override, go to Django Admin "waffle_utils" -> "Waffle flag course overrides".
|
||||
|
||||
Waffle flag: Set this to the flag name (e.g. my_namespace.some_course_feature).
|
||||
Course id: Set this to the course id (e.g. course-v1:edx+100+Demo)
|
||||
Override choice: (Force on/Force off). "Force on" will enable the waffle flag for all users in a course,
|
||||
overriding any behavior configured on the waffle flag itself. "Force off" will disable the waffle flag
|
||||
for all users in a course, overriding any behavior configured on the waffle flag itself. Requires
|
||||
"Enabled" (see below) to apply.
|
||||
Enabled: Must be marked as "enabled" in order for the override to be applied. These settings can't be
|
||||
deleted, so instead, you need to add another disabled override entry to disable the override.
|
||||
|
||||
To configure an org-level override, go to Django Admin "waffle_utils" -> "Waffle flag org overrides".
|
||||
|
||||
Waffle flag: Set this to the flag name (e.g. my_namespace.some_course_feature).
|
||||
Org name: Set this to the organization name (e.g. edx)
|
||||
Override choice: (Force on/Force off). "Force on" will enable the waffle flag for all users in an org's courses,
|
||||
overriding any behavior configured on the waffle flag itself. "Force off" will disable the waffle flag
|
||||
for all users in a org's courses, overriding any behavior configured on the waffle flag itself. Requires
|
||||
"Enabled" (see below) to apply.
|
||||
Enabled: Must be marked as "enabled" in order for the override to be applied. These settings can't be
|
||||
deleted, so instead, you need to add another disabled override entry to disable the override.
|
||||
Represents a single waffle flag that can be forced on/off for a course.
|
||||
|
||||
Deprecated: use the FutureCourseWaffleFlag instead.
|
||||
"""
|
||||
def __init__(self, waffle_namespace, flag_name, module_name=None):
|
||||
log_prefix = ""
|
||||
if not isinstance(waffle_namespace, str):
|
||||
log_prefix = waffle_namespace.log_prefix or log_prefix
|
||||
waffle_namespace = waffle_namespace.name
|
||||
|
||||
def _get_course_override_value(self, course_key):
|
||||
"""
|
||||
Returns True/False if the flag was forced on or off for the provided course. Returns None if the flag was not
|
||||
overridden.
|
||||
|
||||
Note: Has side effect of caching the override value.
|
||||
|
||||
Arguments:
|
||||
course_key (CourseKey): The course to check for override before checking waffle.
|
||||
"""
|
||||
# Import is placed here to avoid model import at project startup.
|
||||
from .models import WaffleFlagCourseOverrideModel, WaffleFlagOrgOverrideModel
|
||||
|
||||
course_cache_key = f"{self.name}.cwaffle.{str(course_key)}"
|
||||
course_override = self.cached_flags().get(course_cache_key)
|
||||
|
||||
if course_override is None:
|
||||
course_override = WaffleFlagCourseOverrideModel.override_value(
|
||||
self.name, course_key
|
||||
)
|
||||
self.cached_flags()[course_cache_key] = course_override
|
||||
|
||||
if course_override == WaffleFlagCourseOverrideModel.ALL_CHOICES.on:
|
||||
return True
|
||||
if course_override == WaffleFlagCourseOverrideModel.ALL_CHOICES.off:
|
||||
return False
|
||||
|
||||
# Since no course-specific override was found, fall back to checking at the org-level.
|
||||
if course_key:
|
||||
org = course_key.org
|
||||
org_cache_key = f"{self.name}.owaffle.{org}"
|
||||
org_override = self.cached_flags().get(org_cache_key)
|
||||
|
||||
if org_override is None:
|
||||
org_override = WaffleFlagOrgOverrideModel.override_value(
|
||||
self.name, org
|
||||
)
|
||||
self.cached_flags()[org_cache_key] = org_override
|
||||
|
||||
if org_override == WaffleFlagOrgOverrideModel.ALL_CHOICES.on:
|
||||
return True
|
||||
if org_override == WaffleFlagOrgOverrideModel.ALL_CHOICES.off:
|
||||
return False
|
||||
|
||||
return None
|
||||
|
||||
def is_enabled(self, course_key=None): # pylint: disable=arguments-differ
|
||||
"""
|
||||
Returns whether or not the flag is enabled within the context of a given course.
|
||||
|
||||
Arguments:
|
||||
course_key (Optional[CourseKey]): The course to check for override before
|
||||
checking waffle. If omitted, check whether the flag is enabled
|
||||
outside the context of any course.
|
||||
"""
|
||||
if course_key:
|
||||
assert isinstance(
|
||||
course_key, CourseKey
|
||||
), "Provided course_key '{}' is not instance of CourseKey.".format(
|
||||
course_key
|
||||
)
|
||||
is_enabled_for_course = self._get_course_override_value(course_key)
|
||||
if is_enabled_for_course is not None:
|
||||
return is_enabled_for_course
|
||||
return super().is_enabled()
|
||||
# Non-namespaced flag_name attribute preserved for backward compatibility
|
||||
self._flag_name = flag_name
|
||||
name = f"{waffle_namespace}.{flag_name}"
|
||||
super().__init__(name, module_name=module_name, log_prefix=log_prefix)
|
||||
set_custom_attribute(
|
||||
"deprecated_legacy_waffle_class",
|
||||
f"{self.__class__.__module__}.{self.__class__.__name__}[{self.name}]"
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ Tests for waffle utils features.
|
||||
# pylint: disable=toggle-missing-annotation
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
import crum
|
||||
import ddt
|
||||
from django.test.client import RequestFactory
|
||||
@@ -11,11 +12,11 @@ from edx_django_utils.cache import RequestCache
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
from waffle.testutils import override_flag
|
||||
|
||||
from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag as LegacyCourseWaffleFlag
|
||||
from openedx.core.djangoapps.waffle_utils.__future__ import FutureCourseWaffleFlag as CourseWaffleFlag
|
||||
from openedx.core.djangoapps.waffle_utils.models import WaffleFlagCourseOverrideModel, WaffleFlagOrgOverrideModel
|
||||
from openedx.core.djangolib.testing.utils import CacheIsolationTestCase
|
||||
|
||||
from .. import CourseWaffleFlag
|
||||
from ..models import WaffleFlagCourseOverrideModel, WaffleFlagOrgOverrideModel
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestCourseWaffleFlag(CacheIsolationTestCase):
|
||||
@@ -33,7 +34,7 @@ class TestCourseWaffleFlag(CacheIsolationTestCase):
|
||||
TEST_COURSE_KEY = CourseKey.from_string(f"{TEST_ORG}/DemoX/Demo_Course")
|
||||
TEST_COURSE_2_KEY = CourseKey.from_string(f"{TEST_ORG}/DemoX/Demo_Course_2")
|
||||
TEST_COURSE_3_KEY = CourseKey.from_string("CollegeX/DemoX/Demo_Course")
|
||||
TEST_COURSE_FLAG = CourseWaffleFlag(NAMESPACE_NAME, FLAG_NAME, __name__)
|
||||
TEST_COURSE_FLAG = CourseWaffleFlag(NAMESPACED_FLAG_NAME, __name__)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
@@ -75,6 +76,44 @@ class TestCourseWaffleFlag(CacheIsolationTestCase):
|
||||
# course which should get the default value of False.
|
||||
assert self.TEST_COURSE_FLAG.is_enabled(self.TEST_COURSE_2_KEY) is False
|
||||
|
||||
@ddt.data(
|
||||
(False, WaffleFlagCourseOverrideModel.ALL_CHOICES.on, True),
|
||||
(True, WaffleFlagCourseOverrideModel.ALL_CHOICES.off, False),
|
||||
(True, WaffleFlagCourseOverrideModel.ALL_CHOICES.unset, True),
|
||||
(False, WaffleFlagCourseOverrideModel.ALL_CHOICES.unset, False),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_legacy_course_waffle_flag(self, waffle_enabled, course_override, result):
|
||||
"""
|
||||
Tests various combinations of a legacy flag being set in waffle and overridden for a course.
|
||||
"""
|
||||
test_legacy_course_flag = LegacyCourseWaffleFlag(
|
||||
self.NAMESPACE_NAME,
|
||||
self.FLAG_NAME,
|
||||
__name__,
|
||||
)
|
||||
with patch.object(WaffleFlagCourseOverrideModel, 'override_value', return_value=course_override):
|
||||
with override_flag(self.NAMESPACED_FLAG_NAME, active=waffle_enabled):
|
||||
# check twice to test that the result is properly cached
|
||||
assert test_legacy_course_flag.is_enabled(self.TEST_COURSE_KEY) == result
|
||||
assert test_legacy_course_flag.is_enabled(self.TEST_COURSE_KEY) == result
|
||||
# result is cached, so override check should happen only once
|
||||
# pylint: disable=no-member
|
||||
WaffleFlagCourseOverrideModel.override_value.assert_called_once_with(
|
||||
self.NAMESPACED_FLAG_NAME,
|
||||
self.TEST_COURSE_KEY
|
||||
)
|
||||
|
||||
# check flag for a second course
|
||||
if course_override == WaffleFlagCourseOverrideModel.ALL_CHOICES.unset:
|
||||
# When course override wasn't set for the first course, the second course will get the same
|
||||
# cached value from waffle.
|
||||
assert test_legacy_course_flag.is_enabled(self.TEST_COURSE_2_KEY) == waffle_enabled
|
||||
else:
|
||||
# When course override was set for the first course, it should not apply to the second
|
||||
# course which should get the default value of False.
|
||||
assert test_legacy_course_flag.is_enabled(self.TEST_COURSE_2_KEY) is False
|
||||
|
||||
@ddt.data(
|
||||
(False, WaffleFlagOrgOverrideModel.ALL_CHOICES.unset, False),
|
||||
(True, WaffleFlagOrgOverrideModel.ALL_CHOICES.unset, True),
|
||||
@@ -196,11 +235,7 @@ class TestCourseWaffleFlag(CacheIsolationTestCase):
|
||||
"""
|
||||
Test flag with undefined waffle flag.
|
||||
"""
|
||||
test_course_flag = CourseWaffleFlag(
|
||||
self.NAMESPACE_NAME,
|
||||
self.FLAG_NAME,
|
||||
__name__,
|
||||
)
|
||||
test_course_flag = CourseWaffleFlag(self.NAMESPACED_FLAG_NAME, __name__)
|
||||
|
||||
with patch.object(
|
||||
WaffleFlagCourseOverrideModel,
|
||||
@@ -222,11 +257,7 @@ class TestCourseWaffleFlag(CacheIsolationTestCase):
|
||||
Test the flag behavior when outside a request context and waffle data undefined.
|
||||
"""
|
||||
crum.set_current_request(None)
|
||||
test_course_flag = CourseWaffleFlag(
|
||||
self.NAMESPACE_NAME,
|
||||
self.FLAG_NAME,
|
||||
__name__,
|
||||
)
|
||||
test_course_flag = CourseWaffleFlag(self.NAMESPACED_FLAG_NAME, __name__)
|
||||
assert test_course_flag.is_enabled(self.TEST_COURSE_KEY) is False
|
||||
|
||||
def test_without_request_and_everyone_active_waffle(self):
|
||||
@@ -234,10 +265,7 @@ class TestCourseWaffleFlag(CacheIsolationTestCase):
|
||||
Test the flag behavior when outside a request context and waffle active for everyone.
|
||||
"""
|
||||
crum.set_current_request(None)
|
||||
test_course_flag = CourseWaffleFlag(
|
||||
self.NAMESPACE_NAME,
|
||||
self.FLAG_NAME,
|
||||
__name__,
|
||||
)
|
||||
|
||||
test_course_flag = CourseWaffleFlag(self.NAMESPACED_FLAG_NAME, __name__)
|
||||
with override_flag(self.NAMESPACED_FLAG_NAME, active=True):
|
||||
assert test_course_flag.is_enabled(self.TEST_COURSE_KEY) is True
|
||||
|
||||
@@ -4,28 +4,28 @@ Unified course experience settings and helper methods.
|
||||
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
from edx_toggles.toggles import LegacyWaffleFlag, LegacyWaffleFlagNamespace
|
||||
from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag
|
||||
from edx_toggles.toggles import WaffleFlag
|
||||
from openedx.core.djangoapps.waffle_utils.__future__ import FutureCourseWaffleFlag as CourseWaffleFlag
|
||||
|
||||
|
||||
# Namespace for course experience waffle flags.
|
||||
WAFFLE_FLAG_NAMESPACE = LegacyWaffleFlagNamespace(name='course_experience')
|
||||
WAFFLE_FLAG_NAMESPACE = 'course_experience'
|
||||
|
||||
# Waffle flag to disable the separate course outline page and full width content.
|
||||
DISABLE_COURSE_OUTLINE_PAGE_FLAG = CourseWaffleFlag( # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
WAFFLE_FLAG_NAMESPACE, 'disable_course_outline_page', __name__
|
||||
f'{WAFFLE_FLAG_NAMESPACE}.disable_course_outline_page', __name__
|
||||
)
|
||||
|
||||
# Waffle flag to enable a single unified "Course" tab.
|
||||
DISABLE_UNIFIED_COURSE_TAB_FLAG = CourseWaffleFlag( # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
WAFFLE_FLAG_NAMESPACE, 'disable_unified_course_tab', __name__
|
||||
f'{WAFFLE_FLAG_NAMESPACE}.disable_unified_course_tab', __name__
|
||||
)
|
||||
|
||||
# Waffle flag to enable the sock on the footer of the home and courseware pages.
|
||||
DISPLAY_COURSE_SOCK_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'display_course_sock', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
DISPLAY_COURSE_SOCK_FLAG = CourseWaffleFlag(f'{WAFFLE_FLAG_NAMESPACE}.display_course_sock', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
|
||||
# Waffle flag to let learners access a course before its start date.
|
||||
COURSE_PRE_START_ACCESS_FLAG = LegacyWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'pre_start_access', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
COURSE_PRE_START_ACCESS_FLAG = WaffleFlag(f'{WAFFLE_FLAG_NAMESPACE}.pre_start_access', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
|
||||
# .. toggle_name: course_experience.enable_course_goals
|
||||
# .. toggle_implementation: CourseWaffleFlag
|
||||
@@ -35,14 +35,12 @@ COURSE_PRE_START_ACCESS_FLAG = LegacyWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'pre_star
|
||||
# .. toggle_creation_date: 2017-09-11
|
||||
# .. toggle_target_removal_date: None
|
||||
# .. toggle_warnings: This temporary feature toggle does not have a target removal date.
|
||||
ENABLE_COURSE_GOALS = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'enable_course_goals', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
ENABLE_COURSE_GOALS = CourseWaffleFlag(f'{WAFFLE_FLAG_NAMESPACE}.enable_course_goals', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
|
||||
# Waffle flag to enable anonymous access to a course
|
||||
SEO_WAFFLE_FLAG_NAMESPACE = LegacyWaffleFlagNamespace(name='seo')
|
||||
SEO_WAFFLE_FLAG_NAMESPACE = 'seo'
|
||||
COURSE_ENABLE_UNENROLLED_ACCESS_FLAG = CourseWaffleFlag( # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
SEO_WAFFLE_FLAG_NAMESPACE,
|
||||
'enable_anonymous_courseware_access',
|
||||
__name__,
|
||||
f'{SEO_WAFFLE_FLAG_NAMESPACE}.enable_anonymous_courseware_access', __name__
|
||||
)
|
||||
|
||||
# .. toggle_name: course_experience.relative_dates
|
||||
@@ -55,7 +53,7 @@ COURSE_ENABLE_UNENROLLED_ACCESS_FLAG = CourseWaffleFlag( # lint-amnesty, pylint
|
||||
# .. toggle_warnings: To set a relative due date for self-paced courses, the weeks_to_complete field for a course run
|
||||
# needs to be set. Currently it can be set through the publisher app.
|
||||
# .. toggle_tickets: https://openedx.atlassian.net/browse/AA-27
|
||||
RELATIVE_DATES_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'relative_dates', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
RELATIVE_DATES_FLAG = CourseWaffleFlag(f'{WAFFLE_FLAG_NAMESPACE}.relative_dates', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
|
||||
# .. toggle_name: course_experience.calendar_sync
|
||||
# .. toggle_implementation: CourseWaffleFlag
|
||||
@@ -69,7 +67,7 @@ RELATIVE_DATES_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'relative_dates',
|
||||
# .. toggle_creation_date: 2021-01-26
|
||||
# .. toggle_target_removal_date: 2021-04-26
|
||||
# .. toggle_tickets: https://openedx.atlassian.net/browse/AA-36
|
||||
CALENDAR_SYNC_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'calendar_sync', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
CALENDAR_SYNC_FLAG = CourseWaffleFlag(f'{WAFFLE_FLAG_NAMESPACE}.calendar_sync', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
|
||||
|
||||
def course_home_page_title(_course):
|
||||
|
||||
@@ -3,7 +3,7 @@ Miscellaneous waffle switches that both LMS and Studio need to access
|
||||
"""
|
||||
|
||||
|
||||
from edx_toggles.toggles import LegacyWaffleSwitchNamespace
|
||||
from edx_toggles.toggles import WaffleSwitch
|
||||
|
||||
# Namespace
|
||||
WAFFLE_NAMESPACE = 'course_experience'
|
||||
@@ -15,18 +15,4 @@ WAFFLE_NAMESPACE = 'course_experience'
|
||||
# .. toggle_description: Used to determine whether to show custom HTML in the sidebar on the internal course about page.
|
||||
# .. toggle_use_cases: open_edx
|
||||
# .. toggle_creation_date: 2018-01-26
|
||||
# TODO: Replace with WaffleSwitch(). See waffle() docstring.
|
||||
ENABLE_COURSE_ABOUT_SIDEBAR_HTML = 'enable_about_sidebar_html'
|
||||
|
||||
|
||||
def waffle():
|
||||
"""
|
||||
Deprecated: Returns the namespaced, cached, audited shared Waffle Switch class.
|
||||
|
||||
IMPORTANT: Do NOT copy this pattern and do NOT use this to reference new switches.
|
||||
Instead, replace the string constant above with the actual switch instance.
|
||||
For example::
|
||||
|
||||
ENABLE_COURSE_ABOUT_SIDEBAR_HTML = WaffleSwitch(f'{WAFFLE_NAMESPACE}.enable_about_sidebar_html')
|
||||
"""
|
||||
return LegacyWaffleSwitchNamespace(name=WAFFLE_NAMESPACE, log_prefix='Course Experience: ')
|
||||
ENABLE_COURSE_ABOUT_SIDEBAR_HTML = WaffleSwitch(f'{WAFFLE_NAMESPACE}.enable_about_sidebar_html', __name__)
|
||||
|
||||
@@ -15,7 +15,7 @@ import pytz
|
||||
from crum import get_current_request, impersonate
|
||||
from django.utils import timezone
|
||||
from django.utils.dateparse import parse_datetime
|
||||
from edx_toggles.toggles import LegacyWaffleFlag, LegacyWaffleFlagNamespace
|
||||
from edx_toggles.toggles import WaffleFlag
|
||||
|
||||
from common.djangoapps.course_modes.models import CourseMode
|
||||
from common.djangoapps.entitlements.models import CourseEntitlement
|
||||
@@ -37,11 +37,7 @@ from common.djangoapps.track import segment
|
||||
# .. toggle_target_removal_date: None
|
||||
# .. toggle_tickets: REVEM-282
|
||||
# .. toggle_warnings: This temporary feature toggle does not have a target removal date.
|
||||
DISCOUNT_APPLICABILITY_FLAG = LegacyWaffleFlag(
|
||||
waffle_namespace=LegacyWaffleFlagNamespace(name='discounts'),
|
||||
flag_name='enable_discounting',
|
||||
module_name=__name__,
|
||||
)
|
||||
DISCOUNT_APPLICABILITY_FLAG = WaffleFlag('discounts.enable_discounting', __name__)
|
||||
|
||||
DISCOUNT_APPLICABILITY_HOLDBACK = 'first_purchase_discount_holdback'
|
||||
REV1008_EXPERIMENT_ID = 16
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
Feature toggles used for effort estimation.
|
||||
"""
|
||||
|
||||
from edx_toggles.toggles import LegacyWaffleFlagNamespace
|
||||
|
||||
from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag
|
||||
from openedx.core.djangoapps.waffle_utils.__future__ import FutureCourseWaffleFlag as CourseWaffleFlag
|
||||
|
||||
|
||||
WAFFLE_FLAG_NAMESPACE = LegacyWaffleFlagNamespace(name='effort_estimation')
|
||||
WAFFLE_FLAG_NAMESPACE = 'effort_estimation'
|
||||
|
||||
# .. toggle_name: effort_estimation.disabled
|
||||
# .. toggle_implementation: CourseWaffleFlag
|
||||
@@ -16,4 +14,4 @@ WAFFLE_FLAG_NAMESPACE = LegacyWaffleFlagNamespace(name='effort_estimation')
|
||||
# estimates), you can turn them off case by case here.
|
||||
# .. toggle_use_cases: opt_out
|
||||
# .. toggle_creation_date: 2021-07-27
|
||||
EFFORT_ESTIMATION_DISABLED_FLAG = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'disabled', __name__)
|
||||
EFFORT_ESTIMATION_DISABLED_FLAG = CourseWaffleFlag(f'{WAFFLE_FLAG_NAMESPACE}.disabled', __name__)
|
||||
|
||||
@@ -13,7 +13,7 @@ from django.core.cache import cache
|
||||
from django.urls import NoReverseMatch, reverse
|
||||
from django.utils.translation import gettext as _
|
||||
from edx_django_utils.cache import TieredCache, get_cache_key
|
||||
from edx_toggles.toggles import LegacyWaffleFlag
|
||||
from edx_toggles.toggles import WaffleFlag
|
||||
from enterprise.api.v1.serializers import EnterpriseCustomerBrandingConfigurationSerializer
|
||||
from enterprise.models import EnterpriseCustomer, EnterpriseCustomerUser
|
||||
from social_django.models import UserSocialAuth
|
||||
@@ -25,7 +25,7 @@ from openedx.core.djangoapps.site_configuration import helpers as configuration_
|
||||
from openedx.core.djangoapps.user_authn.cookies import standard_cookie_settings
|
||||
from openedx.core.djangolib.markup import HTML, Text
|
||||
|
||||
ENTERPRISE_HEADER_LINKS = LegacyWaffleFlag('enterprise', 'enterprise_header_links', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
ENTERPRISE_HEADER_LINKS = WaffleFlag('enterprise.enterprise_header_links', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation
|
||||
|
||||
|
||||
def get_data_consent_share_cache_key(user_id, course_id, enterprise_customer_uuid=None):
|
||||
|
||||
@@ -3,11 +3,11 @@ Toggles for Learner Profile page.
|
||||
"""
|
||||
|
||||
|
||||
from edx_toggles.toggles import LegacyWaffleFlag, LegacyWaffleFlagNamespace
|
||||
from edx_toggles.toggles import WaffleFlag
|
||||
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
||||
|
||||
# Namespace for learner profile waffle flags.
|
||||
WAFFLE_FLAG_NAMESPACE = LegacyWaffleFlagNamespace(name='learner_profile')
|
||||
WAFFLE_FLAG_NAMESPACE = 'learner_profile'
|
||||
|
||||
# Waffle flag to redirect to another learner profile experience.
|
||||
# .. toggle_name: learner_profile.redirect_to_microfrontend
|
||||
@@ -19,7 +19,7 @@ WAFFLE_FLAG_NAMESPACE = LegacyWaffleFlagNamespace(name='learner_profile')
|
||||
# .. toggle_target_removal_date: 2020-12-31
|
||||
# .. toggle_warnings: Also set settings.PROFILE_MICROFRONTEND_URL and site's ENABLE_PROFILE_MICROFRONTEND.
|
||||
# .. toggle_tickets: DEPR-17
|
||||
REDIRECT_TO_PROFILE_MICROFRONTEND = LegacyWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'redirect_to_microfrontend', __name__)
|
||||
REDIRECT_TO_PROFILE_MICROFRONTEND = WaffleFlag(f'{WAFFLE_FLAG_NAMESPACE}.redirect_to_microfrontend', __name__)
|
||||
|
||||
|
||||
def should_redirect_to_profile_microfrontend():
|
||||
|
||||
Reference in New Issue
Block a user