Beispiel #1
0
    def test_is_enterprise_learner(self):
        with mock.patch('django.core.cache.cache.set') as mock_cache_set:
            EnterpriseCustomerUserFactory.create(active=True,
                                                 user_id=self.user.id)
            assert is_enterprise_learner(self.user)
            assert is_enterprise_learner(self.user.id)

        assert mock_cache_set.called
Beispiel #2
0
    def test_is_enterprise_learner_no_enterprise_user(self):
        with mock.patch(
            'django.core.cache.cache.set'
        ) as mock_cache_set:
            assert not is_enterprise_learner(self.user)

        assert not mock_cache_set.called
Beispiel #3
0
def can_show_streak_discount_experiment_coupon(user, course):
    """
    Check whether this combination of user and course
    can receive the AA-759 experiment discount.
    """
    # Course end date needs to be in the future
    if course.has_ended():
        return False

    # Course needs to have a non-expired verified mode
    modes_dict = CourseMode.modes_for_course_dict(course=course,
                                                  include_expired=False)
    if 'verified' not in modes_dict:
        return False

    # Learner needs to be in an upgradeable mode
    try:
        enrollment = CourseEnrollment.objects.get(
            user=user,
            course=course.id,
        )
    except CourseEnrollment.DoesNotExist:
        return False

    if not is_mode_upsellable(user, enrollment):
        return False

    # We can't import this at Django load time within the openedx tests settings context
    from openedx.features.enterprise_support.utils import is_enterprise_learner
    # Don't give discount to enterprise users
    if is_enterprise_learner(user):
        return False

    return True
def can_receive_discount(user, course, discount_expiration_date=None):
    """
    Check all the business logic about whether this combination of user and course
    can receive a discount.
    """
    # Always disable discounts until we are ready to enable this feature
    with impersonate(user):
        if not DISCOUNT_APPLICABILITY_FLAG.is_enabled():
            return False

    # TODO: Add additional conditions to return False here

    # anonymous users should never get the discount
    if user.is_anonymous:
        return False

    # Check if discount has expired
    if not discount_expiration_date:
        discount_expiration_date = get_discount_expiration_date(user, course)

    if discount_expiration_date is None:
        return False

    if discount_expiration_date < timezone.now():
        return False

    # Course end date needs to be in the future
    if course.has_ended():
        return False

    # Course needs to have a non-expired verified mode
    modes_dict = CourseMode.modes_for_course_dict(course=course, include_expired=False)
    verified_mode = modes_dict.get('verified', None)
    if not verified_mode:
        return False

    # Site, Partner, Course or Course Run not excluded from lms-controlled discounts
    if DiscountRestrictionConfig.disabled_for_course_stacked_config(course):
        return False

    # Don't allow users who have enrolled in any courses in non-upsellable
    # modes
    if CourseEnrollment.objects.filter(user=user).exclude(mode__in=CourseMode.UPSELL_TO_VERIFIED_MODES).exists():
        return False

    # Don't allow any users who have entitlements (past or present)
    if CourseEntitlement.objects.filter(user=user).exists():
        return False

    # We can't import this at Django load time within the openedx tests settings context
    from openedx.features.enterprise_support.utils import is_enterprise_learner
    # Don't give discount to enterprise users
    if is_enterprise_learner(user):
        return False

    # Excute holdback
    if _is_in_holdback(user):
        return False

    return True
Beispiel #5
0
def is_secondary_email_feature_enabled_for_user(user):
    """
    Checks to see if secondary email feature is enabled for the given user.

    Returns:
        Boolean value representing the status of secondary email feature.
    """
    # import is placed here to avoid cyclic import.
    from openedx.features.enterprise_support.utils import is_enterprise_learner
    return is_secondary_email_feature_enabled() and is_enterprise_learner(user)
Beispiel #6
0
def is_secondary_email_feature_enabled_for_user(user):
    """
    Checks to see if secondary email feature is enabled for the given user.

    Returns:
        Boolean value representing the status of secondary email feature.
    """
    # import is placed here to avoid cyclic import.
    from openedx.features.enterprise_support.utils import is_enterprise_learner
    return is_secondary_email_feature_enabled() and is_enterprise_learner(user)
Beispiel #7
0
def handle_enterprise_learner_passing_grade(sender, user, course_id, **kwargs):  # pylint: disable=unused-argument
    """
    Listen for a learner passing a course, transmit data to relevant integrated channel
    """
    if enterprise_enabled() and is_enterprise_learner(user):
        kwargs = {
            'username': six.text_type(user.username),
            'course_run_id': six.text_type(course_id)
        }

        transmit_single_learner_data.apply_async(kwargs=kwargs)
Beispiel #8
0
def show_user_demographics(user, enrollments=None, entitlements=None):
    """
    Check if the user should be shown demographics collection fields. Currently limited
    to MicroBachlors Programs' learners who aren't part of an enterprise.
    """
    is_user_in_microbachelors_program = is_user_enrolled_in_program_type(
        user,
        "microbachelors",
        enrollments=enrollments,
        entitlements=entitlements)
    return is_user_in_microbachelors_program and not is_enterprise_learner(
        user)
Beispiel #9
0
def handle_enterprise_learner_subsection(sender, user, course_id, subsection_id, subsection_grade, **kwargs):  # pylint: disable=unused-argument
    """
    Listen for an enterprise learner completing a subsection, transmit data to relevant integrated channel.
    """
    if enterprise_enabled() and is_enterprise_learner(user):
        kwargs = {
            'username': str(user.username),
            'course_run_id': str(course_id),
            'subsection_id': str(subsection_id),
            'grade': str(subsection_grade),
        }

        transmit_single_subsection_learner_data.apply_async(kwargs=kwargs)
Beispiel #10
0
def get_enterprise_event_context(user_id, course_id):
    """
    Creates an enterprise context from a `course_id` anf `user_id`.
    Example Returned Context::
        {
            'enterprise_uuid': '1a0fbcbe-49e5-42f1-8e83-4cddfa592f22'
        }
    Arguments:
        user_id: id of user object.
        course_id: id of course object.
    Returns:
        dict: A dictionary representing the enterprise uuid.
    """
    # Prevent a circular import.
    from openedx.features.enterprise_support.utils import is_enterprise_learner
    context = {}
    if is_enterprise_learner(user_id):
        uuids = EnterpriseCourseEnrollment.get_enterprise_uuids_with_user_and_course(
            str(user_id), str(course_id))
        if uuids:
            context.update({"enterprise_uuid": str(uuids[0])})
    return context
Beispiel #11
0
    def test_is_enterprise_learner_no_enterprise_user(self):
        with mock.patch('django.core.cache.cache.set') as mock_cache_set:
            self.assertFalse(is_enterprise_learner(self.user))

        self.assertFalse(mock_cache_set.called)
Beispiel #12
0
 def test_is_enterprise_learner_enterprise_disabled(self, _, mock_cache_get,
                                                    mock_cache_set):
     assert not is_enterprise_learner(self.user)
     assert not is_enterprise_learner(self.user.id)
     assert not mock_cache_get.called
     assert not mock_cache_set.called
Beispiel #13
0
def activate_account(request, key):
    """
    When link in activation e-mail is clicked
    """
    # If request is in Studio call the appropriate view
    if theming_helpers.get_project_root_name().lower() == 'cms':
        monitoring_utils.set_custom_attribute('student_activate_account',
                                              'cms')
        return activate_account_studio(request, key)

    # TODO: Use custom attribute to determine if there are any `activate_account` calls for cms in Production.
    # If not, the templates wouldn't be needed for cms, but we still need a way to activate for cms tests.
    monitoring_utils.set_custom_attribute('student_activate_account', 'lms')
    activation_message_type = None

    invalid_message = HTML(
        _('{html_start}Your account could not be activated{html_end}'
          'Something went wrong, please <a href="{support_url}">contact support</a> to resolve this issue.'
          )).format(
              support_url=configuration_helpers.get_value(
                  'ACTIVATION_EMAIL_SUPPORT_LINK',
                  settings.ACTIVATION_EMAIL_SUPPORT_LINK)
              or settings.SUPPORT_SITE_LINK,
              html_start=HTML('<p class="message-title">'),
              html_end=HTML('</p>'),
          )

    try:
        registration = Registration.objects.get(activation_key=key)
    except (Registration.DoesNotExist, Registration.MultipleObjectsReturned):
        activation_message_type = 'error'
        messages.error(request,
                       invalid_message,
                       extra_tags='account-activation aa-icon')
    else:
        if request.user.is_authenticated and request.user.id != registration.user.id:
            activation_message_type = 'error'
            messages.error(request,
                           invalid_message,
                           extra_tags='account-activation aa-icon')
        elif registration.user.is_active:
            activation_message_type = 'info'
            messages.info(
                request,
                HTML(
                    _('{html_start}This account has already been activated.{html_end}'
                      )).format(
                          html_start=HTML('<p class="message-title">'),
                          html_end=HTML('</p>'),
                      ),
                extra_tags='account-activation aa-icon',
            )
        else:
            registration.activate()
            # Success message for logged in users.
            message = _(
                '{html_start}Success{html_end} You have activated your account.'
            )

            tracker.emit(
                USER_ACCOUNT_ACTIVATED, {
                    "user_id": registration.user.id,
                    "activation_timestamp": registration.activation_timestamp
                })

            if not request.user.is_authenticated:
                # Success message for logged out users
                message = _(
                    '{html_start}Success! You have activated your account.{html_end}'
                    'You will now receive email updates and alerts from us related to'
                    ' the courses you are enrolled in. Sign In to continue.')

            # Add message for later use.
            activation_message_type = 'success'
            messages.success(
                request,
                HTML(message).format(
                    html_start=HTML('<p class="message-title">'),
                    html_end=HTML('</p>'),
                ),
                extra_tags='account-activation aa-icon',
            )

    # If a safe `next` parameter is provided in the request
    # and it's not the same as the dashboard, redirect there.
    # The `get_next_url_for_login_page()` function will only return a safe redirect URL.
    # If the provided `next` URL is not safe, that function will fill `redirect_to`
    # with a value of `reverse('dashboard')`.
    redirect_url = None
    if request.GET.get('next'):
        redirect_to, root_login_url = get_next_url_for_login_page(
            request, include_host=True)

        # Don't automatically redirect authenticated users to the redirect_url
        # if the `next` value is either:
        # 1. "/dashboard" or
        # 2. "https://{LMS_ROOT_URL}/dashboard" (which we might provide as a value from the AuthN MFE)
        if redirect_to not in (root_login_url + reverse('dashboard'),
                               reverse('dashboard')):
            redirect_url = get_redirect_url_with_host(root_login_url,
                                                      redirect_to)

    if should_redirect_to_authn_microfrontend(
    ) and not request.user.is_authenticated:
        params = {'account_activation_status': activation_message_type}
        if redirect_url:
            params['next'] = redirect_url
        url_path = '/login?{}'.format(urllib.parse.urlencode(params))
        return redirect(settings.AUTHN_MICROFRONTEND_URL + url_path)

    return redirect(redirect_url) if redirect_url and is_enterprise_learner(
        request.user) else redirect('dashboard')