Exemplo n.º 1
0
 def _verify_user(request, userid_in_session):
     """
     Logs an error if the user marked at the time of process_request
     does not match either the current user in the request or the
     given userid_in_session.
     """
     if hasattr(request, 'safe_cookie_verified_user_id'):
         if request.safe_cookie_verified_user_id != request.user.id:
             # The user at response time is expected to be None when the user
             # is logging out. To prevent extra noise in the logs,
             # conditionally set the log level.
             log_func = log.debug if request.user.id is None else log.warning
             log_func((
                 "SafeCookieData user at request '{0}' does not match user at response: '{1}' "
                 "for request path '{2}'").format(
                     request.safe_cookie_verified_user_id,
                     request.user.id,
                     request.path,
                 ), )
             set_custom_attribute("safe_sessions.user_mismatch",
                                  "request-response-mismatch")
         if request.safe_cookie_verified_user_id != userid_in_session:
             log.warning(
                 ("SafeCookieData user at request '{0}' does not match user in session: '{1}' "
                  "for request path '{2}'").format(  # pylint: disable=logging-format-interpolation
                      request.safe_cookie_verified_user_id,
                      userid_in_session,
                      request.path,
                  ), )
             set_custom_attribute("safe_sessions.user_mismatch",
                                  "request-session-mismatch")
Exemplo n.º 2
0
    def try_load_course(self, course_dir, course_ids=None, target_course_id=None):
        '''
        Load a course, keeping track of errors as we go along. If course_ids is not None,
        then reject the course unless its id is in course_ids.
        '''
        # Special-case code here, since we don't have a location for the
        # course before it loads.
        # So, make a tracker to track load-time errors, then put in the right
        # place after the course loads and we have its location
        errorlog = make_error_tracker()
        course_descriptor = None
        try:
            course_descriptor = self.load_course(course_dir, course_ids, errorlog.tracker, target_course_id)
        except Exception as exc:  # pylint: disable=broad-except
            msg = "ERROR: Failed to load courselike '{}': {}".format(
                course_dir.encode("utf-8"), str(exc)
            )
            set_custom_attribute('course_import_failure', f"Courselike load failure: {msg}")
            log.exception(msg)
            errorlog.tracker(msg)
            self.errored_courses[course_dir] = errorlog

        if course_descriptor is None:
            pass
        elif isinstance(course_descriptor, ErrorBlock):
            # Didn't load course.  Instead, save the errors elsewhere.
            self.errored_courses[course_dir] = errorlog
        else:
            self.courses[course_dir] = course_descriptor
            course_descriptor.parent = None
            course_id = self.id_from_descriptor(course_descriptor)
            self._course_errors[course_id] = errorlog
Exemplo n.º 3
0
    def _on_user_authentication_failed(request):
        """
        To be called when user authentication fails when processing
        requests in the middleware. Sets a flag to delete the user's
        cookie and redirects the user to the login page.
        """
        _mark_cookie_for_deletion(request)

        # Mobile apps have custom handling of authentication failures. They
        # should *not* be redirected to the website's login page.
        if is_request_from_mobile_app(request):
            return HttpResponse(status=401)

        # .. toggle_name: REDIRECT_TO_LOGIN_ON_SAFE_SESSION_AUTH_FAILURE
        # .. toggle_implementation: SettingToggle
        # .. toggle_default: True
        # .. toggle_description: Turn this toggle off to roll out new functionality,
        #      which returns a 401 rather than redirecting to login, when HTML is not expected by the client.
        # .. toggle_use_cases: temporary
        # .. toggle_creation_date: 2021-10-18
        # .. toggle_target_removal_date: 2021-10-22
        # .. toggle_tickets: https://openedx.atlassian.net/browse/ARCHBOM-1911
        REDIRECT_TO_LOGIN_ON_SAFE_SESSION_AUTH_FAILURE = getattr(
            settings, 'REDIRECT_TO_LOGIN_ON_SAFE_SESSION_AUTH_FAILURE', True)

        if REDIRECT_TO_LOGIN_ON_SAFE_SESSION_AUTH_FAILURE or 'text/html' in request.META.get(
                'HTTP_ACCEPT', ''):
            set_custom_attribute("safe_sessions.auth_failure",
                                 "redirect_to_login")
            return redirect_to_login(request.path)
        set_custom_attribute("safe_sessions.auth_failure", "401")
        return HttpResponse(status=401)
Exemplo n.º 4
0
    def is_flag_active(self, flag_name, check_before_waffle_callback=None):
        """
        Returns and caches whether the provided flag is active.

        If the flag value is already cached in the request, it is returned.
        If check_before_waffle_callback is supplied, it is called before
            checking waffle.
        If check_before_waffle_callback returns None, or if it is not supplied,
            then waffle is used to check the flag.

        Important: Caching for the check_before_waffle_callback must be handled
            by the callback itself.

        Note: A waffle flag's default is False if not defined. If you think you
            need the default to be True, see the module docstring for
            alternatives.

        Arguments:
            flag_name (String): The name of the flag to check.
            check_before_waffle_callback (function): (Optional) A function that
                will be checked before continuing on to waffle. If
                check_before_waffle_callback(namespaced_flag_name) returns True
                or False, it is returned. If it returns None, then waffle is
                used.

        """
        # validate arguments
        namespaced_flag_name = self._namespaced_name(flag_name)

        if check_before_waffle_callback:
            value = check_before_waffle_callback(namespaced_flag_name)
            if value is not None:
                # Do not cache value for the callback, because the key might be different.
                # The callback needs to handle its own caching if it wants it.
                self._set_waffle_flag_attribute(namespaced_flag_name, value)
                return value

        value = self._cached_flags.get(namespaced_flag_name)
        if value is not None:
            self._set_waffle_flag_attribute(namespaced_flag_name, value)
            return value

        request = crum.get_current_request()
        if not request:
            log.warning(u"%sFlag '%s' accessed without a request",
                        self.log_prefix, namespaced_flag_name)
            # Return the Flag's Everyone value if not in a request context.
            # Note: this skips the cache as the value might be different
            # in a normal request context. This case seems to occur when
            # a page redirects to a 404, or for celery workers.
            value = self._is_flag_active_for_everyone(namespaced_flag_name)
            self._set_waffle_flag_attribute(namespaced_flag_name, value)
            set_custom_attribute('warn_flag_no_request_return_value', value)
            return value

        value = flag_is_active(request, namespaced_flag_name)
        self._cached_flags[namespaced_flag_name] = value

        self._set_waffle_flag_attribute(namespaced_flag_name, value)
        return value
Exemplo n.º 5
0
    def _set_code_owner_attribute_from_current_transaction(self, request):
        """
        Uses the current transaction name to set the code owner attribute.

        Side-effects:
            Sets code_owner_transaction_name custom attribute, used to determine code_owner

        Returns:
            (str, str): (code_owner, error_message), where at least one of these should be None

        """
        if not is_code_owner_mappings_configured():
            return None, None

        try:
            # Example: openedx.core.djangoapps.contentserver.middleware:StaticContentServer
            transaction_name = get_current_transaction().name
            if not transaction_name:
                return None, 'No current transaction name found.'
            set_custom_attribute('code_owner_transaction_name',
                                 transaction_name)
            module_name = transaction_name.split(':')[0]
            code_owner = get_code_owner_from_module(module_name)
            return code_owner, None
        except Exception as e:  # pylint: disable=broad-except
            return None, str(e)
Exemplo n.º 6
0
 def _verify_user(request, userid_in_session):
     """
     Logs an error if the user marked at the time of process_request
     does not match either the current user in the request or the
     given userid_in_session.
     """
     if hasattr(request, 'safe_cookie_verified_user_id'):
         if hasattr(request.user, 'real_user'):
             # If a view overrode the request.user with a masqueraded user, this will
             #   revert/clean-up that change during response processing.
             request.user = request.user.real_user
         # The user at response time is expected to be None when the user
         # is logging out.  We won't log that.
         if request.safe_cookie_verified_user_id != request.user.id and request.user.id is not None:
             log.warning(
                 ("SafeCookieData user at request '{}' does not match user at response: '{}' "
                  "for request path '{}'").format(  # pylint: disable=logging-format-interpolation
                      request.safe_cookie_verified_user_id,
                      request.user.id,
                      request.path,
                  ), )
             set_custom_attribute("safe_sessions.user_mismatch",
                                  "request-response-mismatch")
         # The user session at response time is expected to be None when the user
         # is logging out.  We won't log that.
         if request.safe_cookie_verified_user_id != userid_in_session and userid_in_session is not None:
             log.warning(
                 ("SafeCookieData user at request '{}' does not match user in session: '{}' "
                  "for request path '{}'").format(  # pylint: disable=logging-format-interpolation
                      request.safe_cookie_verified_user_id,
                      userid_in_session,
                      request.path,
                  ), )
             set_custom_attribute("safe_sessions.user_mismatch",
                                  "request-session-mismatch")
Exemplo n.º 7
0
def _check_user_auth_flow(site, user):
    """
    Check if user belongs to an allowed domain and not whitelisted
    then ask user to login through allowed domain SSO provider.
    """
    if user and ENABLE_LOGIN_USING_THIRDPARTY_AUTH_ONLY.is_enabled():
        allowed_domain = site.configuration.get_value(
            'THIRD_PARTY_AUTH_ONLY_DOMAIN', '').lower()
        email_parts = user.email.split('@')
        if len(email_parts) != 2:
            # User has a nonstandard email so we record their id.
            # we don't record their e-mail in case there is sensitive info accidentally
            # in there.
            set_custom_attribute('login_tpa_domain_shortcircuit_user_id',
                                 user.id)
            log.warn(
                "User %s has nonstandard e-mail. Shortcircuiting THIRD_PART_AUTH_ONLY_DOMAIN check.",
                user.id)
            return
        user_domain = email_parts[1].strip().lower()

        # If user belongs to allowed domain and not whitelisted then user must login through allowed domain SSO
        if user_domain == allowed_domain and not AllowedAuthUser.objects.filter(
                site=site, email=user.email).exists():
            if not should_redirect_to_logistration_mircrofrontend():
                msg = _create_message(site, None, allowed_domain)
            else:
                root_url = configuration_helpers.get_value(
                    'LMS_ROOT_URL', settings.LMS_ROOT_URL)
                msg = _create_message(site, root_url, allowed_domain)
            raise AuthFailedError(msg)
    def _set_request_auth_type_guess_attribute(self, request):
        """
        Add custom attribute 'request_auth_type_guess' for the authentication type used.

        NOTE: This is a best guess at this point.  Possible values include:
            no-user
            unauthenticated
            jwt/bearer/other-token-type
            jwt-cookie
            session-or-other (catch all)

        """
        if not hasattr(request, 'user') or not request.user:
            auth_type = 'no-user'
        elif not request.user.is_authenticated:
            auth_type = 'unauthenticated'
        elif 'HTTP_AUTHORIZATION' in request.META and request.META[
                'HTTP_AUTHORIZATION']:
            token_parts = request.META['HTTP_AUTHORIZATION'].split()
            # Example: "JWT eyJhbGciO..."
            if len(token_parts) == 2:
                auth_type = token_parts[0].lower(
                )  # 'jwt' or 'bearer' (for example)
            else:
                auth_type = 'other-token-type'
        elif USE_JWT_COOKIE_HEADER in request.META and jwt_cookie_name(
        ) in request.COOKIES:
            auth_type = 'jwt-cookie'
        else:
            auth_type = 'session-or-other'
        monitoring.set_custom_attribute('request_auth_type_guess', auth_type)
 def _set_request_referer_attribute(self, request):
     """
     Add custom attribute 'request_referer' for http referer.
     """
     if 'HTTP_REFERER' in request.META and request.META['HTTP_REFERER']:
         monitoring.set_custom_attribute('request_referer',
                                         request.META['HTTP_REFERER'])
Exemplo n.º 10
0
def associate_by_email_if_login_api(auth_entry,
                                    backend,
                                    details,
                                    user,
                                    current_partial=None,
                                    *args,
                                    **kwargs):  # lint-amnesty, pylint: disable=keyword-arg-before-vararg
    """
    This pipeline step associates the current social auth with the user with the
    same email address in the database.  It defers to the social library's associate_by_email
    implementation, which verifies that only a single database user is associated with the email.

    This association is done ONLY if the user entered the pipeline through a LOGIN API.
    """
    if auth_entry == AUTH_ENTRY_LOGIN_API:
        # Temporary custom attribute to help ensure there is no usage.
        set_custom_attribute('deprecated_auth_entry_login_api', True)
        association_response = associate_by_email(backend, details, user,
                                                  *args, **kwargs)
        if (association_response and association_response.get('user')
                and association_response['user'].is_active):
            # Only return the user matched by email if their email has been activated.
            # Otherwise, an illegitimate user can create an account with another user's
            # email address and the legitimate user would now login to the illegitimate
            # account.
            return association_response
Exemplo n.º 11
0
def _check_user_auth_flow(site, user):
    """
    Check if user belongs to an allowed domain and not whitelisted
    then ask user to login through allowed domain SSO provider.
    """
    if user and ENABLE_LOGIN_USING_THIRDPARTY_AUTH_ONLY.is_enabled():
        allowed_domain = site.configuration.get_value('THIRD_PARTY_AUTH_ONLY_DOMAIN', '').lower()
        email_parts = user.email.split('@')
        if len(email_parts) != 2:
            # User has a nonstandard email so we record their id.
            # we don't record their e-mail in case there is sensitive info accidentally
            # in there.
            set_custom_attribute('login_tpa_domain_shortcircuit_user_id', user.id)
            log.warn("User %s has nonstandard e-mail. Shortcircuiting THIRD_PART_AUTH_ONLY_DOMAIN check.", user.id)
            return
        user_domain = email_parts[1].strip().lower()

        # If user belongs to allowed domain and not whitelisted then user must login through allowed domain SSO
        if user_domain == allowed_domain and not AllowedAuthUser.objects.filter(site=site, email=user.email).exists():
            msg = Text(_(
                u'As {allowed_domain} user, You must login with your {allowed_domain} '
                u'{link_start}{provider} account{link_end}.'
            )).format(
                allowed_domain=allowed_domain,
                link_start=HTML("<a href='{tpa_provider_link}'>").format(
                    tpa_provider_link='{dashboard_url}?tpa_hint={tpa_hint}'.format(
                        dashboard_url=reverse('dashboard'),
                        tpa_hint=site.configuration.get_value('THIRD_PARTY_AUTH_ONLY_HINT'),
                    )
                ),
                provider=site.configuration.get_value('THIRD_PARTY_AUTH_ONLY_PROVIDER'),
                link_end=HTML("</a>")
            )
            raise AuthFailedError(msg)
Exemplo n.º 12
0
def import_waffle_switch():
    """
    Helper method that imports WaffleSwitch from edx-platform at runtime.
    WARNING: This method is now deprecated and should not be relied upon.
    """
    set_custom_attribute("deprecated_edx_ora2", "import_waffle_switch")
    return WaffleSwitch
Exemplo n.º 13
0
    def authenticate(self, request):
        try:
            user_and_auth = super().authenticate(request)

            # Unauthenticated, CSRF validation not required
            if not user_and_auth:
                return user_and_auth

            # Not using JWT cookies, CSRF validation not required
            use_jwt_cookie_requested = request.META.get(USE_JWT_COOKIE_HEADER)
            if not use_jwt_cookie_requested:
                return user_and_auth

            self.enforce_csrf(request)

            # CSRF passed validation with authenticated user
            return user_and_auth

        except jwt.InvalidTokenError as token_error:
            # Note: I think this case is not used, but will monitor the custom attribute to verify.
            set_custom_attribute(
                'jwt_auth_failed',
                'InvalidTokenError:{}'.format(repr(token_error)))
            raise exceptions.AuthenticationFailed() from token_error
        except Exception as exception:
            # Errors in production do not need to be logged (as they may be noisy),
            # but debug logging can help quickly resolve issues during development.
            logger.debug('Failed JWT Authentication,', exc_info=exception)
            # Note: I think this case should only include AuthenticationFailed and PermissionDenied,
            #   but will monitor the custom attribute to verify.
            set_custom_attribute('jwt_auth_failed',
                                 'Exception:{}'.format(repr(exception)))
            raise
Exemplo n.º 14
0
def _update_publish_report(course_outline: CourseOutlineData,
                           content_errors: List[ContentErrorData],
                           course_context: CourseContext):
    """
    Record ContentErrors for this course publish. Deletes previous errors.
    """
    set_custom_attribute('learning_sequences.api.num_content_errors', len(content_errors))
    learning_context = course_context.learning_context
    try:
        # Normal path if we're updating a PublishReport
        publish_report = learning_context.publish_report
        publish_report.num_errors = len(content_errors)
        publish_report.num_sections = len(course_outline.sections)
        publish_report.num_sequences = len(course_outline.sequences)
        publish_report.content_errors.all().delete()
    except PublishReport.DoesNotExist:
        # Case where we're creating it for the first time.
        publish_report = PublishReport(
            learning_context=learning_context,
            num_errors=len(content_errors),
            num_sections=len(course_outline.sections),
            num_sequences=len(course_outline.sequences),
        )

    publish_report.save()
    publish_report.content_errors.bulk_create([
        ContentError(
            publish_report=publish_report,
            usage_key=error_data.usage_key,
            message=error_data.message,
        )
        for error_data in content_errors
    ])
Exemplo n.º 15
0
    def authenticate(self, request):
        set_custom_attribute("BearerAuthentication", "Failed")  # default value
        if not self.get_user_info_url():
            logger.warning('The setting OAUTH2_USER_INFO_URL is invalid!')
            set_custom_attribute("BearerAuthentication", "NoURL")
            return None
        set_custom_attribute("BearerAuthentication_user_info_url",
                             self.get_user_info_url())
        auth = get_authorization_header(request).split()

        if not auth or auth[0].lower() != b'bearer':
            set_custom_attribute("BearerAuthentication", "None")
            return None

        if len(auth) == 1:
            raise exceptions.AuthenticationFailed(
                'Invalid token header. No credentials provided.')
        if len(auth) > 2:
            raise exceptions.AuthenticationFailed(
                'Invalid token header. Token string should not contain spaces.'
            )

        output = self.authenticate_credentials(auth[1].decode('utf8'))
        set_custom_attribute("BearerAuthentication", "Success")
        return output
Exemplo n.º 16
0
def replace_course_outline(course_outline: CourseOutlineData,
                           content_errors: Optional[List[ContentErrorData]] = None):
    """
    Replace the model data stored for the Course Outline with the contents of
    course_outline (a CourseOutlineData). Record any content errors.

    This isn't particularly optimized at the moment.
    """
    log.info(
        "Replacing CourseOutline for %s (version %s, %d sequences)",
        course_outline.course_key, course_outline.published_version, len(course_outline.sequences)
    )
    set_custom_attribute('learning_sequences.api.course_id', str(course_outline.course_key))

    if content_errors is None:
        content_errors = []

    with transaction.atomic():
        # Update or create the basic CourseContext...
        course_context = _update_course_context(course_outline)

        # Wipe out the CourseSectionSequences join+ordering table
        course_context.section_sequences.all().delete()

        _update_sections(course_outline, course_context)
        _update_sequences(course_outline, course_context)
        _update_course_section_sequences(course_outline, course_context)
        _update_publish_report(course_outline, content_errors, course_context)
Exemplo n.º 17
0
 def _monitor_value(self, flag_name, value):
     """
     Monitoring method preserved for backward compatibility. You should use `WaffleFlag.set_monitor_value` instead.
     """
     set_custom_attribute("deprecated_edx_toggles_waffle",
                          "WaffleFlagNamespace._monitor_value")
     return NewWaffleFlag(self._namespaced_name(flag_name),
                          module_name=__name__).set_monitor_value(value)
Exemplo n.º 18
0
    def get_adapter(self, request):
        """
        Returns the appropriate adapter based on the OAuth client linked to the request.
        """
        client_id = self._get_client_id(request)
        monitoring_utils.set_custom_attribute('oauth_client_id', client_id)

        return self.dot_adapter
Exemplo n.º 19
0
def _compute_time_fields(expires_in):
    """
    Returns (iat, exp) tuple to be used as time-related values in a token.
    """
    now = int(time())
    expires_in = expires_in or settings.JWT_AUTH['JWT_EXPIRATION']
    set_custom_attribute('jwt_expires_in', expires_in)
    return now, now + expires_in
Exemplo n.º 20
0
    def __init__(self, waffle_namespace, switch_name, module_name=None):
        if not isinstance(waffle_namespace, str):
            waffle_namespace = waffle_namespace.name
        set_custom_attribute("deprecated_edx_toggles_waffle", "WaffleSwitch")

        self._switch_name = switch_name
        name = "{}.{}".format(waffle_namespace, switch_name)
        super().__init__(name, module_name=module_name)
Exemplo n.º 21
0
 def __init__(self, name, log_prefix=None):
     super().__init__(name, log_prefix=log_prefix)
     warnings.warn(
         "Importing WaffleFlagNamespace from waffle_utils is deprecated. Instead, import from edx_toggles.toggles.",
         DeprecationWarning,
         stacklevel=2,
     )
     set_custom_attribute("deprecated_waffle_utils",
                          "WaffleFlagNamespace[{}]".format(name))
Exemplo n.º 22
0
 def set_monitor_value(self, _value):
     """
     This used to send waffle flag values to monitoring, but is now a no-op. This method is preserved for backward
     compatibility.
     """
     set_custom_attribute(
         "deprecated_waffle_method",
         "WaffleFlag[{}].set_monitor_value".format(self.name),
     )
Exemplo n.º 23
0
 def __init__(self, waffle_namespace, flag_name, module_name=None):
     super().__init__(waffle_namespace, flag_name, module_name=module_name)
     warnings.warn(
         "Importing WaffleFlag from waffle_utils is deprecated. Instead, import from edx_toggles.toggles.",
         DeprecationWarning,
         stacklevel=2,
     )
     set_custom_attribute("deprecated_waffle_utils",
                          "WaffleFlag[{}]".format(self.name))
Exemplo n.º 24
0
    def get_schedules_with_target_date_by_bin_and_orgs(
            self, order_by='enrollment__user__id'):
        """
        Returns Schedules with the target_date, related to Users whose id matches the bin_num, and filtered by org_list.

        Arguments:
        order_by -- string for field to sort the resulting Schedules by
        """
        target_day = _get_datetime_beginning_of_day(self.target_datetime)
        schedule_day_equals_target_day_filter = {
            'courseenrollment__schedule__{}__gte'.format(self.schedule_date_field):
            target_day,
            'courseenrollment__schedule__{}__lt'.format(self.schedule_date_field):
            target_day + datetime.timedelta(days=1),
        }
        users = User.objects.filter(
            courseenrollment__is_active=True,
            is_active=True,
            **schedule_day_equals_target_day_filter).annotate(
                id_mod=self.bin_num_for_user_id(F('id'))).filter(
                    id_mod=self.bin_num)

        schedule_day_equals_target_day_filter = {
            '{}__gte'.format(self.schedule_date_field):
            target_day,
            '{}__lt'.format(self.schedule_date_field):
            target_day + datetime.timedelta(days=1),
        }
        schedules = Schedule.objects.select_related(
            'enrollment__user__profile',
            'enrollment__course',
            'enrollment__fbeenrollmentexclusion',
        ).filter(Q(enrollment__course__end__isnull=True)
                 | Q(enrollment__course__end__gte=self.current_datetime),
                 self.experience_filter,
                 enrollment__user__in=users,
                 enrollment__is_active=True,
                 active=True,
                 **schedule_day_equals_target_day_filter).order_by(order_by)

        schedules = self.filter_by_org(schedules)

        if "read_replica" in settings.DATABASES:
            schedules = schedules.using("read_replica")

        LOG.info('Query = %r', schedules.query.sql_with_params())

        with function_trace('schedule_query_set_evaluation'):
            # This will run the query and cache all of the results in memory.
            num_schedules = len(schedules)

        LOG.info('Number of schedules = %d', num_schedules)

        # This should give us a sense of the volume of data being processed by each task.
        set_custom_attribute('num_schedules', num_schedules)

        return schedules
Exemplo n.º 25
0
def warn_deprecated_import(old_import, new_import):
    """
    Warn that a module is being imported from its old location.
    """
    set_custom_attribute("deprecated_edx_platform_import", old_import)
    warnings.warn(
        DeprecatedEdxPlatformImportWarning(old_import, new_import),
        stacklevel=3,  # Should surface the line that is doing the importing.
    )
Exemplo n.º 26
0
 def namespaced_flag_name(self):
     """
     Preserved for backward compatibility.
     """
     set_custom_attribute(
         "deprecated_waffle_legacy_method",
         f"WaffleFlag[{self.name}].namespaced_flag_name",
     )
     return self.name
Exemplo n.º 27
0
 def _cached_flags(self):
     """
     Legacy property used by CourseWaffleFlag.
     """
     set_custom_attribute(
         "deprecated_waffle_legacy_method",
         f"WaffleFlagNamespace[{self.name}]._cached_flags",
     )
     return NewWaffleFlag.cached_flags()
Exemplo n.º 28
0
 def _monitor_value(self, _flag_name, _value):
     """
     Monitoring method preserved for backward compatibility. This is a no-op now that `WaffleFlag.set_monitor_value`
     is deprecated.
     """
     set_custom_attribute(
         "deprecated_waffle_legacy_method",
         f"WaffleFlagNamespace[{self.name}]._monitor_value",
     )
Exemplo n.º 29
0
 def namespaced_switch_name(self):
     """
     This is now equivalent to the switch name.
     """
     set_custom_attribute(
         "deprecated_waffle_legacy_method",
         f"WaffleSwitch[{self.name}].namespaced_switch_name",
     )
     return self.name
Exemplo n.º 30
0
 def switch_name(self):
     """
     Non-namespaced switch_name attribute preserved for backward compatibility.
     """
     set_custom_attribute(
         "deprecated_waffle_legacy_method",
         f"WaffleSwitch[{self.name}].switch_name",
     )
     return self._switch_name