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=u'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( waffle_namespace=namespace, flag_name=ENABLE_VEM_PIPELINE, module_name=__name__, ) }
from openedx.features.discounts.models import DiscountPercentageConfig, DiscountRestrictionConfig from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.track import segment # .. toggle_name: discounts.enable_discounting # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Toggle discounts always being disabled # .. toggle_use_cases: temporary # .. toggle_creation_date: 2019-4-16 # .. 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_HOLDBACK = 'first_purchase_discount_holdback' REV1008_EXPERIMENT_ID = 16 def get_discount_expiration_date(user, course): """ Returns the date when the discount expires for the user. Returns none if the user is not enrolled. """ # anonymous users should never get the discount if user.is_anonymous: return None
def student_dashboard(request): # lint-amnesty, pylint: disable=too-many-statements """ Provides the LMS dashboard view TODO: This is lms specific and does not belong in common code. Note: To load the all courses set course_limit=None as parameter in GET. If its not None then default course limit will be used that is set in configuration Arguments: request: The request object. Returns: The dashboard response. """ landing_page = request.POST.get( 'https://rc360service-q6uoj7vcrq-uc.a.run.app/r1/landingpage/getLandingPageDetails', '') # return render_to_response(landing_page) # decrypt_message(landing_page) # print(landing_page,"") user = request.user if not UserProfile.objects.filter(user=user).exists(): return redirect(reverse('account_settings')) platform_name = configuration_helpers.get_value("platform_name", settings.PLATFORM_NAME) enable_verified_certificates = configuration_helpers.get_value( 'ENABLE_VERIFIED_CERTIFICATES', settings.FEATURES.get('ENABLE_VERIFIED_CERTIFICATES')) display_course_modes_on_dashboard = configuration_helpers.get_value( 'DISPLAY_COURSE_MODES_ON_DASHBOARD', settings.FEATURES.get('DISPLAY_COURSE_MODES_ON_DASHBOARD', True)) activation_email_support_link = configuration_helpers.get_value( 'ACTIVATION_EMAIL_SUPPORT_LINK', settings.ACTIVATION_EMAIL_SUPPORT_LINK) or settings.SUPPORT_SITE_LINK hide_dashboard_courses_until_activated = configuration_helpers.get_value( 'HIDE_DASHBOARD_COURSES_UNTIL_ACTIVATED', settings.FEATURES.get('HIDE_DASHBOARD_COURSES_UNTIL_ACTIVATED', False)) empty_dashboard_message = configuration_helpers.get_value( 'EMPTY_DASHBOARD_MESSAGE', None) disable_course_limit = request and 'course_limit' in request.GET course_limit = get_dashboard_course_limit( ) if not disable_course_limit else None # Get the org whitelist or the org blacklist for the current site site_org_whitelist, site_org_blacklist = get_org_black_and_whitelist_for_site( ) course_enrollments = list( get_course_enrollments(user, site_org_whitelist, site_org_blacklist, course_limit)) # Get the entitlements for the user and a mapping to all available sessions for that entitlement # If an entitlement has no available sessions, pass through a mock course overview object (course_entitlements, course_entitlement_available_sessions, unfulfilled_entitlement_pseudo_sessions ) = get_filtered_course_entitlements(user, site_org_whitelist, site_org_blacklist) # Record how many courses there are so that we can get a better # understanding of usage patterns on prod. monitoring_utils.accumulate('num_courses', len(course_enrollments)) # Sort the enrollment pairs by the enrollment date course_enrollments.sort(key=lambda x: x.created, reverse=True) # Retrieve the course modes for each course enrolled_course_ids = [ enrollment.course_id for enrollment in course_enrollments ] __, unexpired_course_modes = CourseMode.all_and_unexpired_modes_for_courses( enrolled_course_ids) course_modes_by_course = { course_id: {mode.slug: mode for mode in modes} for course_id, modes in iteritems(unexpired_course_modes) } # Check to see if the student has recently enrolled in a course. # If so, display a notification message confirming the enrollment. enrollment_message = _create_recent_enrollment_message( course_enrollments, course_modes_by_course) course_optouts = Optout.objects.filter(user=user).values_list('course_id', flat=True) # Display activation message activate_account_message = '' if not user.is_active: activate_account_message = Text( _("Check your {email_start}{email}{email_end} inbox for an account activation link from {platform_name}. " "If you need help, contact {link_start}{platform_name} Support{link_end}." ) ).format( platform_name=platform_name, email_start=HTML("<strong>"), email_end=HTML("</strong>"), email=user.email, link_start=HTML( "<a target='_blank' href='{activation_email_support_link}'>"). format( activation_email_support_link=activation_email_support_link, ), link_end=HTML("</a>"), ) enterprise_message = get_dashboard_consent_notification( request, user, course_enrollments) # Display a message guiding the user to their Enterprise's Learner Portal if enabled enterprise_learner_portal_enabled_message = get_enterprise_learner_portal_enabled_message( request) recovery_email_message = recovery_email_activation_message = None if is_secondary_email_feature_enabled(): try: pending_email = PendingSecondaryEmailChange.objects.get(user=user) # lint-amnesty, pylint: disable=unused-variable except PendingSecondaryEmailChange.DoesNotExist: try: account_recovery_obj = AccountRecovery.objects.get(user=user) # lint-amnesty, pylint: disable=unused-variable except AccountRecovery.DoesNotExist: recovery_email_message = Text( _("Add a recovery email to retain access when single-sign on is not available. " "Go to {link_start}your Account Settings{link_end}.") ).format(link_start=HTML( "<a href='{account_setting_page}'>").format( account_setting_page=reverse('account_settings'), ), link_end=HTML("</a>")) else: recovery_email_activation_message = Text( _("Recovery email is not activated yet. " "Kindly visit your email and follow the instructions to activate it." )) # Disable lookup of Enterprise consent_required_course due to ENT-727 # Will re-enable after fixing WL-1315 consent_required_courses = set() enterprise_customer_name = None # Account activation message account_activation_messages = [ message for message in messages.get_messages(request) if 'account-activation' in message.tags ] # Global staff can see what courses encountered an error on their dashboard staff_access = False errored_courses = {} if has_access(user, 'staff', 'global'): # Show any courses that encountered an error on load staff_access = True errored_courses = modulestore().get_errored_courses() show_courseware_links_for = { enrollment.course_id: has_access(request.user, 'load', enrollment.course_overview) for enrollment in course_enrollments } # Find programs associated with course runs being displayed. This information # is passed in the template context to allow rendering of program-related # information on the dashboard. meter = ProgramProgressMeter(request.site, user, enrollments=course_enrollments) ecommerce_service = EcommerceService() inverted_programs = meter.invert_programs() urls, programs_data = {}, {} bundles_on_dashboard_flag = LegacyWaffleFlag(experiments_namespace, u'bundles_on_dashboard', __name__) # TODO: Delete this code and the relevant HTML code after testing LEARNER-3072 is complete if bundles_on_dashboard_flag.is_enabled() and inverted_programs and list( inverted_programs.items()): if len(course_enrollments) < 4: for program in inverted_programs.values(): try: program_uuid = program[0]['uuid'] program_data = get_programs(uuid=program_uuid) program_data = ProgramDataExtender(program_data, request.user).extend() skus = program_data.get('skus') checkout_page_url = ecommerce_service.get_checkout_page_url( *skus) program_data[ 'completeProgramURL'] = checkout_page_url + '&bundle=' + program_data.get( 'uuid') programs_data[program_uuid] = program_data except: # pylint: disable=bare-except pass # Construct a dictionary of course mode information # used to render the course list. We re-use the course modes dict # we loaded earlier to avoid hitting the database. course_mode_info = { enrollment.course_id: complete_course_mode_info( enrollment.course_id, enrollment, modes=course_modes_by_course[enrollment.course_id]) for enrollment in course_enrollments } # Determine the per-course verification status # This is a dictionary in which the keys are course locators # and the values are one of: # # VERIFY_STATUS_NEED_TO_VERIFY # VERIFY_STATUS_SUBMITTED # VERIFY_STATUS_APPROVED # VERIFY_STATUS_MISSED_DEADLINE # # Each of which correspond to a particular message to display # next to the course on the dashboard. # # If a course is not included in this dictionary, # there is no verification messaging to display. verify_status_by_course = check_verify_status_by_course( user, course_enrollments) cert_statuses = { enrollment.course_id: cert_info(request.user, enrollment.course_overview) for enrollment in course_enrollments } # only show email settings for Mongo course and when bulk email is turned on show_email_settings_for = frozenset( enrollment.course_id for enrollment in course_enrollments if (is_bulk_email_feature_enabled(enrollment.course_id))) # Verification Attempts # Used to generate the "you must reverify for course x" banner verification_status = IDVerificationService.user_status(user) verification_errors = get_verification_error_reasons_for_display( verification_status['error']) # Gets data for midcourse reverifications, if any are necessary or have failed statuses = ["approved", "denied", "pending", "must_reverify"] reverifications = reverification_info(statuses) enrolled_courses_either_paid = frozenset( enrollment.course_id for enrollment in course_enrollments if enrollment.is_paid_course()) # If there are *any* denied reverifications that have not been toggled off, # we'll display the banner denied_banner = any(item.display for item in reverifications["denied"]) # get list of courses having pre-requisites yet to be completed courses_having_prerequisites = frozenset( enrollment.course_id for enrollment in course_enrollments if enrollment.course_overview.pre_requisite_courses) courses_requirements_not_met = get_pre_requisite_courses_not_completed( user, courses_having_prerequisites) if 'notlive' in request.GET: redirect_message = _( "The course you are looking for does not start until {date}." ).format(date=request.GET['notlive']) elif 'course_closed' in request.GET: redirect_message = _( "The course you are looking for is closed for enrollment as of {date}." ).format(date=request.GET['course_closed']) elif 'access_response_error' in request.GET: # This can be populated in a generalized way with fields from access response errors redirect_message = request.GET['access_response_error'] else: redirect_message = '' valid_verification_statuses = [ 'approved', 'must_reverify', 'pending', 'expired' ] display_sidebar_on_dashboard = verification_status['status'] in valid_verification_statuses and \ verification_status['should_display'] # Filter out any course enrollment course cards that are associated with fulfilled entitlements for entitlement in [ e for e in course_entitlements if e.enrollment_course_run is not None ]: course_enrollments = [ enr for enr in course_enrollments if entitlement.enrollment_course_run.course_id != enr.course_id ] # landing_page =request.POST['https://rc360service-q6uoj7vcrq-uc.a.run.app/r1/landingpage/getLandingPageDetails'] context = { 'urls': urls, 'landing_page': landing_page, 'programs_data': programs_data, 'enterprise_message': enterprise_message, 'consent_required_courses': consent_required_courses, 'enterprise_customer_name': enterprise_customer_name, 'enrollment_message': enrollment_message, 'redirect_message': Text(redirect_message), 'account_activation_messages': account_activation_messages, 'activate_account_message': activate_account_message, 'course_enrollments': course_enrollments, 'course_entitlements': course_entitlements, 'course_entitlement_available_sessions': course_entitlement_available_sessions, 'unfulfilled_entitlement_pseudo_sessions': unfulfilled_entitlement_pseudo_sessions, 'course_optouts': course_optouts, 'staff_access': staff_access, 'errored_courses': errored_courses, 'show_courseware_links_for': show_courseware_links_for, 'all_course_modes': course_mode_info, 'cert_statuses': cert_statuses, 'credit_statuses': _credit_statuses(user, course_enrollments), 'show_email_settings_for': show_email_settings_for, 'reverifications': reverifications, 'verification_display': verification_status['should_display'], 'verification_status': verification_status['status'], 'verification_expiry': verification_status['verification_expiry'], 'verification_status_by_course': verify_status_by_course, 'verification_errors': verification_errors, 'denied_banner': denied_banner, 'billing_email': settings.PAYMENT_SUPPORT_EMAIL, 'user': user, 'logout_url': reverse('logout'), 'platform_name': platform_name, 'enrolled_courses_either_paid': enrolled_courses_either_paid, 'provider_states': [], 'courses_requirements_not_met': courses_requirements_not_met, 'nav_hidden': True, 'inverted_programs': inverted_programs, 'show_program_listing': ProgramsApiConfig.is_enabled(), 'show_dashboard_tabs': True, 'disable_courseware_js': True, 'display_course_modes_on_dashboard': enable_verified_certificates and display_course_modes_on_dashboard, 'display_sidebar_on_dashboard': display_sidebar_on_dashboard, 'display_sidebar_account_activation_message': not (user.is_active or hide_dashboard_courses_until_activated), 'display_dashboard_courses': (user.is_active or not hide_dashboard_courses_until_activated), 'empty_dashboard_message': empty_dashboard_message, 'recovery_email_message': recovery_email_message, 'recovery_email_activation_message': recovery_email_activation_message, 'enterprise_learner_portal_enabled_message': enterprise_learner_portal_enabled_message, 'show_load_all_courses_link': show_load_all_courses_link(user, course_limit, course_enrollments), # TODO START: clean up as part of REVEM-199 (START) 'course_info': get_dashboard_course_info(user, course_enrollments), # TODO START: clean up as part of REVEM-199 (END) } context_from_plugins = get_plugins_view_context( ProjectType.LMS, COURSE_DASHBOARD_PLUGIN_VIEW_NAME, context) context.update(context_from_plugins) course = None context.update(get_experiment_user_metadata_context( course, user, )) if ecommerce_service.is_enabled(request.user): context.update({ 'use_ecommerce_payment_flow': True, 'ecommerce_payment_page': ecommerce_service.payment_page_url(), }) # Gather urls for course card resume buttons. resume_button_urls = ['' for entitlement in course_entitlements] for url in get_resume_urls_for_enrollments(user, course_enrollments).values(): resume_button_urls.append(url) # There must be enough urls for dashboard.html. Template creates course # cards for "enrollments + entitlements". context.update({'resume_button_urls': resume_button_urls}) return render_to_response('dashboard.html', context)
# TODO: After removing this flag, add a migration to remove waffle flag in a follow-up deployment. ENABLE_CHECKLISTS_QUALITY = CourseWaffleFlag( # lint-amnesty, pylint: disable=toggle-missing-annotation waffle_namespace=waffle_flags(), flag_name='enable_checklists_quality', module_name=__name__, ) SHOW_REVIEW_RULES_FLAG = CourseWaffleFlag( # lint-amnesty, pylint: disable=toggle-missing-annotation waffle_namespace=waffle_flags(), flag_name='show_review_rules', module_name=__name__, ) # Waffle flag to redirect to the library authoring MFE. # .. toggle_name: contentstore.library_authoring_mfe # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Toggles the new micro-frontend-based implementation of the library authoring experience. # .. toggle_use_cases: temporary, open_edx # .. toggle_creation_date: 2020-08-03 # .. toggle_target_removal_date: 2020-12-31 # .. toggle_warnings: Also set settings.LIBRARY_AUTHORING_MICROFRONTEND_URL and ENABLE_LIBRARY_AUTHORING_MICROFRONTEND. # .. toggle_tickets: https://openedx.atlassian.net/wiki/spaces/COMM/pages/1545011241/BD-14+Blockstore+Powered+Content+Libraries+Taxonomies REDIRECT_TO_LIBRARY_AUTHORING_MICROFRONTEND = LegacyWaffleFlag( waffle_namespace=waffle_flags(), flag_name='library_authoring_mfe', module_name=__name__, )
try: import newrelic.agent except ImportError: newrelic = None # pylint: disable=invalid-name # HACK: This shouldn't be hard-coded to two types # OBSOLETE: This obsoletes 'type' class_priority = ['video', 'problem'] # Make '_' a no-op so we can scrape strings. Using lambda instead of # `django.utils.translation.ugettext_noop` because Django cannot be imported in this file _ = lambda text: text TIMED_EXAM_GATING_WAFFLE_FLAG = LegacyWaffleFlag( waffle_namespace="xmodule", flag_name='rev_1377_rollout', module_name=__name__, ) class SequenceFields: # lint-amnesty, pylint: disable=missing-class-docstring has_children = True completion_mode = XBlockCompletionMode.AGGREGATOR # NOTE: Position is 1-indexed. This is silly, but there are now student # positions saved on prod, so it's not easy to fix. position = Integer(help="Last tab viewed in this sequence", scope=Scope.user_state) due = Date( display_name=_("Due Date"),
""" Toggles for verify_student app """ from edx_toggles.toggles import LegacyWaffleFlag, LegacyWaffleFlagNamespace # Namespace for verify_students waffle flags. WAFFLE_FLAG_NAMESPACE = LegacyWaffleFlagNamespace(name='verify_student') # Waffle flag to use new email templates for sending ID verification emails. # .. toggle_name: verify_student.use_new_email_templates # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Supports staged rollout to students for a new email templates # implementation for ID verification. # .. toggle_use_cases: temporary, open_edx # .. toggle_creation_date: 2020-06-25 # .. toggle_target_removal_date: None # .. toggle_warnings: This temporary feature toggle does not have a target removal date. # .. toggle_tickets: PROD-1639 USE_NEW_EMAIL_TEMPLATES = LegacyWaffleFlag( waffle_namespace=WAFFLE_FLAG_NAMESPACE, flag_name='use_new_email_templates', module_name=__name__, ) def use_new_templates_for_id_verification_emails(): return USE_NEW_EMAIL_TEMPLATES.is_enabled()
from openedx.core.lib.api.view_utils import DeveloperErrorViewMixin from common.djangoapps.student.models import CourseEnrollment from common.djangoapps.track import segment # .. toggle_name: experiments.mobile_upsell_rev934 # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Toggle mobile upsell enabled # .. toggle_use_cases: temporary # .. toggle_creation_date: 2019-09-05 # .. toggle_target_removal_date: None # .. toggle_tickets: REV-934 # .. toggle_warnings: This temporary feature toggle does not have a target removal date. MOBILE_UPSELL_FLAG = LegacyWaffleFlag( waffle_namespace=LegacyWaffleFlagNamespace(name=u'experiments'), flag_name=u'mobile_upsell_rev934', module_name=__name__, ) MOBILE_UPSELL_EXPERIMENT = 'mobile_upsell_experiment' class Rev934(DeveloperErrorViewMixin, APIView): """ **Use Cases** Request upsell information for mobile app users **Example Requests** GET /api/experiments/v0/custom/REV-934/?course_id={course_key_string}
""" Toggles for Course API. """ from edx_toggles.toggles import LegacyWaffleFlag, LegacyWaffleFlagNamespace COURSE_BLOCKS_API_NAMESPACE = LegacyWaffleFlagNamespace( name='course_blocks_api') # .. toggle_name: course_blocks_api.hide_access_denials # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Waffle flag to hide access denial messages in the course blocks. # .. toggle_use_cases: temporary, open_edx # .. toggle_creation_date: 2019-09-27 # .. toggle_target_removal_date: None # .. toggle_warnings: This temporary feature toggle does not have a target removal date. # .. toggle_tickets: None HIDE_ACCESS_DENIALS_FLAG = LegacyWaffleFlag( waffle_namespace=COURSE_BLOCKS_API_NAMESPACE, flag_name='hide_access_denials', module_name=__name__, )
# Namespace for instructor waffle flags. WAFFLE_FLAG_NAMESPACE = LegacyWaffleFlagNamespace(name=WAFFLE_NAMESPACE) # Waffle flag enable new data download UI on specific course. # .. toggle_name: instructor.enable_data_download_v2 # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: instructor # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2020-07-8 # .. toggle_target_removal_date: None # .. toggle_warnings: ?? # .. toggle_tickets: PROD-1309 DATA_DOWNLOAD_V2 = LegacyWaffleFlag( waffle_namespace=WAFFLE_FLAG_NAMESPACE, flag_name='enable_data_download_v2', module_name=__name__, ) # Waffle flag to use optimised is_small_course. # .. toggle_name: verify_student.optimised_is_small_course # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Supports staged rollout to improved is_small_course method. # .. toggle_category: instructor # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2020-07-02 # .. toggle_target_removal_date: None # .. toggle_warnings: n/a # .. toggle_tickets: PROD-1740 # .. toggle_status: supported
# 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 COURSE_EXPERIENCE_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 COURSE_EXPERIENCE_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 # 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 # .. toggle_name: course_experience.enable_course_goals # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False # .. toggle_description: Used to determine whether or not to use course goals for the particular course. # .. toggle_use_cases: opt_out, temporary # .. 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 # Waffle flag to control the display of the hero SHOW_UPGRADE_MSG_ON_COURSE_HOME = CourseWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'show_upgrade_msg_on_course_home', __name__) # lint-amnesty, pylint: disable=toggle-missing-annotation # Waffle flag to control the display of the upgrade deadline message
# Waffle flag to disable the separate course outline page and full width content. DISABLE_COURSE_OUTLINE_PAGE_FLAG = CourseWaffleFlag( COURSE_EXPERIENCE_WAFFLE_FLAG_NAMESPACE, 'disable_course_outline_page', __name__) # Waffle flag to enable a single unified "Course" tab. DISABLE_UNIFIED_COURSE_TAB_FLAG = CourseWaffleFlag( COURSE_EXPERIENCE_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__) # 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__) # .. toggle_name: course_experience.enable_course_goals # .. toggle_implementation: CourseWaffleFlag # .. toggle_default: False # .. toggle_description: Used to determine whether or not to use course goals for the particular course. # .. toggle_use_cases: opt_out, temporary # .. 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__) # Waffle flag to control the display of the hero SHOW_UPGRADE_MSG_ON_COURSE_HOME = CourseWaffleFlag( WAFFLE_FLAG_NAMESPACE, 'show_upgrade_msg_on_course_home', __name__)
module_name=__name__) # Namespace for studio dashboard waffle flags. WAFFLE_NAMESPACE = 'contentstore' WAFFLE_FLAG_NAMESPACE = LegacyWaffleFlagNamespace(name=WAFFLE_NAMESPACE, log_prefix='Contentstore: ') # .. toggle_name: split_library_on_studio_dashboard # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Enables data new view for library on studio dashboard. # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2020-07-8 # .. toggle_tickets: TNL-7536 SPLIT_LIBRARY_ON_DASHBOARD = LegacyWaffleFlag( waffle_namespace=LegacyWaffleFlagNamespace(name=WAFFLE_NAMESPACE), flag_name='split_library_on_studio_dashboard', module_name=__name__) # .. toggle_name: bypass_olx_failure # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Enables bypassing olx validation failures during course import. # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2021-04-15 # .. toggle_target_removal_date: 2021-05-15 # .. toggle_tickets: TNL-8214 BYPASS_OLX_FAILURE = LegacyWaffleFlag( waffle_namespace=LegacyWaffleFlagNamespace(name=WAFFLE_NAMESPACE), flag_name='bypass_olx_failure', module_name=__name__)
) # Waffle flag to use optimised is_small_course. # .. toggle_name: verify_student.optimised_is_small_course # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Supports staged rollout to improved is_small_course method. # .. toggle_category: instructor # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2020-07-02 # .. toggle_target_removal_date: None # .. toggle_warnings: n/a # .. toggle_tickets: PROD-1740 # .. toggle_status: supported OPTIMISED_IS_SMALL_COURSE = LegacyWaffleFlag( waffle_namespace=WAFFLE_FLAG_NAMESPACE, flag_name='optimised_is_small_course', module_name=__name__, ) def data_download_v2_is_enabled(course_key): """ check if data download v2 is enabled. """ return DATA_DOWNLOAD_V2.is_enabled(course_key) def use_optimised_is_small_course(): return OPTIMISED_IS_SMALL_COURSE.is_enabled()
from django.test.client import RequestFactory from django.utils.deprecation import MiddlewareMixin from edx_django_utils.monitoring import set_custom_attribute from opaque_keys import InvalidKeyError from opaque_keys.edx.keys import CourseKey from six.moves.urllib.parse import urlparse from edx_toggles.toggles import LegacyWaffleFlag, LegacyWaffleFlagNamespace from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers # accommodates course api urls, excluding any course api routes that do not fall under v*/courses, such as v1/blocks. COURSE_REGEX = re.compile(r'^(.*?/courses/)(?!v[0-9]+/[^/]+){}'.format( settings.COURSE_ID_PATTERN)) WAFFLE_FLAG_NAMESPACE = LegacyWaffleFlagNamespace(name='request_utils') CAPTURE_COOKIE_SIZES = LegacyWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'capture_cookie_sizes', __name__) log = logging.getLogger(__name__) def get_request_or_stub(): """ Return the current request or a stub request. If called outside the context of a request, construct a fake request that can be used to build an absolute URI. This is useful in cases where we need to pass in a request object but don't have an active request (for example, in tests, celery tasks, and XBlocks). """ request = crum.get_current_request()
""" from edx_toggles.toggles import LegacyWaffleFlag from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers # .. toggle_name: order_history.redirect_to_microfrontend # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Supports staged rollout of a new micro-frontend-based implementation of the order history page. # .. toggle_use_cases: temporary, open_edx # .. toggle_creation_date: 2019-04-11 # .. toggle_target_removal_date: 2020-12-31 # .. 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__) def should_redirect_to_order_history_microfrontend(): return ( configuration_helpers.get_value('ENABLE_ORDER_HISTORY_MICROFRONTEND') and REDIRECT_TO_ORDER_HISTORY_MICROFRONTEND.is_enabled()) # .. toggle_name: account.redirect_to_microfrontend # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Supports staged rollout of a new micro-frontend-based implementation of the account page. # Its action can be overridden using site's ENABLE_ACCOUNT_MICROFRONTEND setting. # .. toggle_use_cases: temporary, open_edx # .. toggle_creation_date: 2019-04-30
"ENABLE_EXPORT_GIT", default=False, module_name=__name__) # Namespace for studio dashboard waffle flags. WAFFLE_NAMESPACE = 'contentstore' WAFFLE_FLAG_NAMESPACE = LegacyWaffleFlagNamespace(name=WAFFLE_NAMESPACE, log_prefix='Contentstore: ') # Waffle flag to split library to new view. # .. toggle_name: split_library_on_studio_dashboard # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Studio dashboard # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2020-07-8 # .. toggle_target_removal_date: None # .. toggle_warnings: ?? # .. toggle_tickets: TNL-7536 SPLIT_LIBRARY_ON_DASHBOARD = LegacyWaffleFlag( waffle_namespace=LegacyWaffleFlagNamespace(name=WAFFLE_NAMESPACE), flag_name='split_library_on_studio_dashboard', module_name=__name__) def split_library_view_on_dashboard(): """ check if data new view for library is enabled on studio dashboard. """ return SPLIT_LIBRARY_ON_DASHBOARD.is_enabled()
try: import newrelic.agent except ImportError: newrelic = None # pylint: disable=invalid-name # HACK: This shouldn't be hard-coded to two types # OBSOLETE: This obsoletes 'type' class_priority = ['video', 'problem'] # Make '_' a no-op so we can scrape strings. Using lambda instead of # `django.utils.translation.ugettext_noop` because Django cannot be imported in this file _ = lambda text: text TIMED_EXAM_GATING_WAFFLE_FLAG = LegacyWaffleFlag( # lint-amnesty, pylint: disable=toggle-missing-annotation waffle_namespace="xmodule", flag_name='rev_1377_rollout', module_name=__name__, ) class SequenceFields: # lint-amnesty, pylint: disable=missing-class-docstring has_children = True completion_mode = XBlockCompletionMode.AGGREGATOR # NOTE: Position is 1-indexed. This is silly, but there are now student # positions saved on prod, so it's not easy to fix. position = Integer(help="Last tab viewed in this sequence", scope=Scope.user_state) due = Date( display_name=_("Due Date"), help=_("Enter the date by which problems are due."),
WAFFLE_NAMESPACE = 'contentstore' WAFFLE_FLAG_NAMESPACE = LegacyWaffleFlagNamespace(name=WAFFLE_NAMESPACE, log_prefix='Contentstore: ') # Waffle flag to split library to new view. # .. toggle_name: split_library_on_studio_dashboard # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Studio dashboard # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2020-07-8 # .. toggle_target_removal_date: None # .. toggle_warnings: ?? # .. toggle_tickets: TNL-7536 SPLIT_LIBRARY_ON_DASHBOARD = LegacyWaffleFlag( waffle_namespace=LegacyWaffleFlagNamespace(name=WAFFLE_NAMESPACE), flag_name='split_library_on_studio_dashboard', module_name=__name__) # Waffle flag to enable olx validation during course import. # .. toggle_name: course_import_olx_validation # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Studio Import # .. toggle_use_cases: open_edx # .. toggle_creation_date: 2021-04-01 # .. toggle_target_removal_date: 2021-05-01 # .. toggle_warnings: ?? # .. toggle_tickets: TNL-8151 COURSE_IMPORT_OLX_VALIDATION = LegacyWaffleFlag( waffle_namespace=LegacyWaffleFlagNamespace(name=WAFFLE_NAMESPACE), flag_name='course_import_olx_validation',
MARKETING_EMAILS_OPT_IN = 'marketing_emails_opt_in' # used to announce a registration REGISTER_USER = Signal(providing_args=["user", "registration"]) # .. toggle_name: registration.enable_failure_logging # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Enable verbose logging of registration failure messages # .. toggle_use_cases: temporary # .. 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__, ) REAL_IP_KEY = 'openedx.core.djangoapps.util.ratelimit.real_ip' @transaction.non_atomic_requests def create_account_with_params(request, params): """ Given a request and a dict of parameters (which may or may not have come from the request), create an account for the requesting user, including creating a comments service user object and sending an activation email. This also takes external/third-party auth into account, updates that as necessary, and authenticates the user for the request's session. Does not return anything.
""" Contains configuration for schedules app """ from edx_toggles.toggles import (LegacyWaffleFlag, LegacyWaffleFlagNamespace, LegacyWaffleSwitch, LegacyWaffleSwitchNamespace) from openedx.core.djangoapps.waffle_utils import CourseWaffleFlag WAFFLE_FLAG_NAMESPACE = LegacyWaffleFlagNamespace(name='schedules') WAFFLE_SWITCH_NAMESPACE = LegacyWaffleSwitchNamespace(name='schedules') CREATE_SCHEDULE_WAFFLE_FLAG = CourseWaffleFlag( waffle_namespace=WAFFLE_FLAG_NAMESPACE, flag_name='create_schedules_for_course', module_name=__name__, ) COURSE_UPDATE_WAFFLE_FLAG = CourseWaffleFlag( waffle_namespace=WAFFLE_FLAG_NAMESPACE, flag_name='send_updates_for_course', module_name=__name__, ) DEBUG_MESSAGE_WAFFLE_FLAG = LegacyWaffleFlag(WAFFLE_FLAG_NAMESPACE, 'enable_debugging', __name__) COURSE_UPDATE_SHOW_UNSUBSCRIBE_WAFFLE_SWITCH = LegacyWaffleSwitch( WAFFLE_SWITCH_NAMESPACE, 'course_update_show_unsubscribe', __name__)
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 enterprise.api.v1.serializers import EnterpriseCustomerBrandingConfigurationSerializer from enterprise.models import EnterpriseCustomer, EnterpriseCustomerUser from social_django.models import UserSocialAuth from common.djangoapps import third_party_auth from common.djangoapps.student.helpers import get_next_url_for_login_page from lms.djangoapps.branding.api import get_privacy_url from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers 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 def get_data_consent_share_cache_key(user_id, course_id, enterprise_customer_uuid=None): """ Returns cache key for data sharing consent needed against user_id, course_id and enterprise_customer_uuid """ cache_key_params = dict( type='data_sharing_consent_needed', user_id=user_id, course_id=course_id, ) if enterprise_customer_uuid: cache_key_params['enterprise_customer_uuid'] = enterprise_customer_uuid
# TODO: clean up as part of REVEM-199 (START) experiments_namespace = LegacyWaffleFlagNamespace(name=u'experiments') # .. toggle_name: experiments.add_programs # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Toggle for adding the current course's program information to user metadata # .. toggle_use_cases: temporary # .. toggle_creation_date: 2019-2-25 # .. toggle_target_removal_date: None # .. toggle_tickets: REVEM-63, REVEM-198 # .. toggle_warnings: This temporary feature toggle does not have a target removal date. PROGRAM_INFO_FLAG = LegacyWaffleFlag( waffle_namespace=experiments_namespace, flag_name=u'add_programs', module_name=__name__, ) # .. toggle_name: experiments.add_dashboard_info # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Toggle for adding info about each course to the dashboard metadata # .. toggle_use_cases: temporary # .. toggle_creation_date: 2019-3-28 # .. toggle_target_removal_date: None # .. toggle_tickets: REVEM-118 # .. toggle_warnings: This temporary feature toggle does not have a target removal date. DASHBOARD_INFO_FLAG = LegacyWaffleFlag(experiments_namespace, u'add_dashboard_info', __name__) # TODO END: clean up as part of REVEM-199 (End)
from django.urls import NoReverseMatch, reverse from django.utils.translation import ugettext as _ from edx_django_utils.cache import TieredCache, get_cache_key from edx_toggles.toggles import LegacyWaffleFlag from enterprise.api.v1.serializers import EnterpriseCustomerBrandingConfigurationSerializer from enterprise.models import EnterpriseCustomer, EnterpriseCustomerUser from social_django.models import UserSocialAuth from common.djangoapps import third_party_auth from lms.djangoapps.branding.api import get_privacy_url from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers from openedx.core.djangoapps.user_authn.cookies import standard_cookie_settings from openedx.core.djangolib.markup import HTML, Text from common.djangoapps.student.helpers import get_next_url_for_login_page ENTERPRISE_HEADER_LINKS = LegacyWaffleFlag('enterprise', 'enterprise_header_links', __name__) def get_data_consent_share_cache_key(user_id, course_id): """ Returns cache key for data sharing consent needed against user_id and course_id """ return get_cache_key(type='data_sharing_consent_needed', user_id=user_id, course_id=course_id) def get_is_enterprise_cache_key(user_id): """ Returns cache key for the enterprise learner validation method needed against user_id.
""" Toggles for Learner Profile page. """ from edx_toggles.toggles import LegacyWaffleFlag, LegacyWaffleFlagNamespace 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 to redirect to another learner profile experience. # .. toggle_name: learner_profile.redirect_to_microfrontend # .. toggle_implementation: WaffleFlag # .. toggle_default: False # .. toggle_description: Supports staged rollout of a new micro-frontend-based implementation of the profile page. # .. toggle_use_cases: temporary, open_edx # .. toggle_creation_date: 2019-02-19 # .. 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__) def should_redirect_to_profile_microfrontend(): return (configuration_helpers.get_value('ENABLE_PROFILE_MICROFRONTEND') and REDIRECT_TO_PROFILE_MICROFRONTEND.is_enabled())