Пример #1
0
    def get_verification_context(self, request, course):
        course_key = CourseKey.from_string(unicode(course.id))

        # Establish whether the course has a verified mode
        available_modes = CourseMode.modes_for_course_dict(unicode(course.id))
        has_verified_mode = CourseMode.has_verified_mode(available_modes)

        # Establish whether the user is already enrolled
        is_already_verified = CourseEnrollment.is_enrolled_as_verified(request.user, course_key)

        # Establish whether the verification deadline has already passed
        verification_deadline = VerifiedUpgradeDeadlineDate(course, request.user)
        deadline_has_passed = verification_deadline.deadline_has_passed()

        # If this proves its worth, we can internationalize and display for more than English speakers.
        show_course_sock = (
            has_verified_mode and not is_already_verified and
            not deadline_has_passed and get_language() == 'en'
        )

        # Get information about the upgrade
        course_price = get_cosmetic_verified_display_price(course)
        upgrade_url = EcommerceService().upgrade_url(request.user, course_key)

        context = {
            'show_course_sock': show_course_sock,
            'course_price': course_price,
            'course_id': course.id,
            'upgrade_url': upgrade_url,
        }

        return context
Пример #2
0
 def register_alerts(self, request, course):
     """
     Registers an alert if the verification deadline is approaching.
     """
     upgrade_price = get_cosmetic_verified_display_price(course)
     if not UPGRADE_DEADLINE_MESSAGE.is_enabled(course.id) or not self.is_enabled or not upgrade_price:
         return
     days_left_to_upgrade = (self.date - self.current_time).days
     if self.date > self.current_time and days_left_to_upgrade <= settings.COURSE_MESSAGE_ALERT_DURATION_IN_DAYS:
         CourseHomeMessages.register_info_message(
             request,
             Text(_(
                 'In order to qualify for a certificate, you must meet all course grading '
                 'requirements, upgrade before the course deadline, and successfully verify '
                 'your identity on {platform_name} if you have not done so already.{button_panel}'
             )).format(
                 platform_name=settings.PLATFORM_NAME,
                 button_panel=HTML(
                     '<div class="message-actions">'
                     '<a class="btn btn-upgrade"'
                     'data-creative="original_message" data-position="course_message"'
                     'href="{upgrade_url}">{upgrade_label}</a>'
                     '</div>'
                 ).format(
                     upgrade_url=self.link,
                     upgrade_label=Text(_('Upgrade ({upgrade_price})')).format(upgrade_price=upgrade_price),
                 )
             ),
             title=Text(_(
                 "Don't forget, you have {time_remaining_string} left to upgrade to a Verified Certificate."
             )).format(
                 time_remaining_string=self.time_remaining_string,
             )
         )
Пример #3
0
def get_experiment_user_metadata_context(course, user):
    """
    Return a context dictionary with the keys used by the user_metadata.html.
    """
    enrollment_mode = None
    enrollment_time = None
    enrollment = None
    try:
        enrollment = CourseEnrollment.objects.select_related(
            'course'
        ).get(user_id=user.id, course_id=course.id)
        if enrollment.is_active:
            enrollment_mode = enrollment.mode
            enrollment_time = enrollment.created
    except CourseEnrollment.DoesNotExist:
        pass  # Not enrolled, used the default None values

    upgrade_link, upgrade_date = check_and_get_upgrade_link_and_date(user, enrollment, course)
    has_staff_access = has_staff_access_to_preview_mode(user, course)

    return {
        'upgrade_link': upgrade_link,
        'upgrade_price': unicode(get_cosmetic_verified_display_price(course)),
        'enrollment_mode': enrollment_mode,
        'enrollment_time': enrollment_time,
        'pacing_type': 'self_paced' if course.self_paced else 'instructor_paced',
        'upgrade_deadline': upgrade_date,
        'course_key': course.id,
        'course_start': course.start,
        'course_end': course.end,
        'has_staff_access': has_staff_access,
    }
Пример #4
0
def get_base_experiment_metadata_context(course, user, enrollment, user_enrollments, audit_enrollments):
    """
    Return a context dictionary with the keys used by dashboard_metadata.html and user_metadata.html
    """
    enrollment_mode = None
    enrollment_time = None
    # TODO: clean up as part of REVEM-199 (START)
    program_key = get_program_context(course, user_enrollments, audit_enrollments)
    # TODO: clean up as part of REVEM-199 (END)
    if enrollment and enrollment.is_active:
        enrollment_mode = enrollment.mode
        enrollment_time = enrollment.created

    # upgrade_link and upgrade_date should be None if user has passed their dynamic pacing deadline.
    upgrade_link, upgrade_date = check_and_get_upgrade_link_and_date(user, enrollment, course)

    return {
        'upgrade_link': upgrade_link,
        'upgrade_price': six.text_type(get_cosmetic_verified_display_price(course)),
        'enrollment_mode': enrollment_mode,
        'enrollment_time': enrollment_time,
        'pacing_type': 'self_paced' if course.self_paced else 'instructor_paced',
        'upgrade_deadline': upgrade_date,
        'audit_access_deadline': get_audit_access_expiration(user, course),
        'course_key': course.id,
        'course_start': course.start,
        'course_end': course.end,
        # TODO: clean up as part of REVEM-199 (START)
        'program_key_fields': program_key,
        # TODO: clean up as part of REVEM-199 (END)
    }
Пример #5
0
    def get_verification_context(self, request, course):
        course_key = CourseKey.from_string(unicode(course.id))

        # Establish whether the course has a verified mode
        available_modes = CourseMode.modes_for_course_dict(unicode(course.id))
        has_verified_mode = CourseMode.has_verified_mode(available_modes)

        # Establish whether the user is already enrolled
        is_already_verified = CourseEnrollment.is_enrolled_as_verified(request.user, course_key)

        # Establish whether the verification deadline has already passed
        verification_deadline = VerifiedUpgradeDeadlineDate(course, request.user)
        deadline_has_passed = verification_deadline.deadline_has_passed()

        # If this proves its worth, we can internationalize and display for more than English speakers.
        show_course_sock = (
            has_verified_mode and not is_already_verified and
            not deadline_has_passed and get_language() == 'en'
        )

        # Get the price of the course and format correctly
        course_price = get_cosmetic_verified_display_price(course)

        context = {
            'show_course_sock': show_course_sock,
            'course_price': course_price,
            'course_id': course.id
        }

        return context
Пример #6
0
def get_experiment_user_metadata_context(course, user):
    """
    Return a context dictionary with the keys used by the user_metadata.html.
    """
    enrollment_mode = None
    enrollment_time = None
    try:
        enrollment = CourseEnrollment.objects.get(user_id=user.id,
                                                  course_id=course.id)
        if enrollment.is_active:
            enrollment_mode = enrollment.mode
            enrollment_time = enrollment.created
    except CourseEnrollment.DoesNotExist:
        pass  # Not enrolled, used the default None values

    upgrade_data = check_and_get_upgrade_link(user, course.id)

    return {
        'upgrade_link': upgrade_data and upgrade_data.link,
        'upgrade_price': get_cosmetic_verified_display_price(course),
        'enrollment_mode': enrollment_mode,
        'enrollment_time': enrollment_time,
        'pacing_type':
        'self_paced' if course.self_paced else 'instructor_paced',
        'upgrade_deadline': upgrade_data and upgrade_data.date,
        'course_key': course.id,
        'course_start': course.start,
        'course_end': course.end,
    }
Пример #7
0
 def register_alerts(self, request, course):
     """
     Registers an alert if the verification deadline is approaching.
     """
     upgrade_price = get_cosmetic_verified_display_price(course)
     if not UPGRADE_DEADLINE_MESSAGE.is_enabled(
             course.id) or not self.is_enabled or not upgrade_price:
         return
     days_left_to_upgrade = (self.date - self.current_time).days
     if self.date > self.current_time and days_left_to_upgrade <= settings.COURSE_MESSAGE_ALERT_DURATION_IN_DAYS:
         CourseHomeMessages.register_info_message(
             request,
             Text(
                 _('In order to qualify for a certificate, you must meet all course grading '
                   'requirements, upgrade before the course deadline, and successfully verify '
                   'your identity on {platform_name} if you have not done so already.{button_panel}'
                   )
             ).format(
                 platform_name=settings.PLATFORM_NAME,
                 button_panel=HTML(
                     '<div class="message-actions">'
                     '<a class="btn btn-upgrade"'
                     'data-creative="original_message" data-position="course_message"'
                     'href="{upgrade_url}">{upgrade_label}</a>'
                     '</div>').format(
                         upgrade_url=self.link,
                         upgrade_label=Text(
                             _('Upgrade ({upgrade_price})')).format(
                                 upgrade_price=upgrade_price),
                     )),
             title=Text(
                 _("Don't forget, you have {time_remaining_string} left to upgrade to a Verified Certificate."
                   )).format(
                       time_remaining_string=self.time_remaining_string, ))
Пример #8
0
def get_experiment_user_metadata_context(course, user):
    """
    Return a context dictionary with the keys used by the user_metadata.html.
    """
    enrollment_mode = None
    enrollment_time = None
    enrollment = None
    # TODO: clean up as part of REVO-28 (START)
    has_non_audit_enrollments = None
    # TODO: clean up as part of REVO-28 (END)
    try:
        # TODO: clean up as part of REVO-28 (START)
        user_enrollments = CourseEnrollment.objects.select_related(
            'course').filter(user_id=user.id)
        audit_enrollments = user_enrollments.filter(mode='audit')
        has_non_audit_enrollments = (len(audit_enrollments) !=
                                     len(user_enrollments))
        # TODO: clean up as part of REVO-28 (END)
        enrollment = CourseEnrollment.objects.select_related('course').get(
            user_id=user.id, course_id=course.id)
        if enrollment.is_active:
            enrollment_mode = enrollment.mode
            enrollment_time = enrollment.created
    except CourseEnrollment.DoesNotExist:
        pass  # Not enrolled, used the default None values

    upgrade_link, upgrade_date = check_and_get_upgrade_link_and_date(
        user, enrollment, course)
    has_staff_access = has_staff_access_to_preview_mode(user, course.id)
    forum_roles = []
    if user.is_authenticated:
        forum_roles = list(
            Role.objects.filter(
                users=user,
                course_id=course.id).values_list('name').distinct())

    # get user partition data
    partition_groups = get_all_partitions_for_course(course)
    user_partitions = get_user_partition_groups(course.id, partition_groups,
                                                user, 'name')

    return {
        'upgrade_link': upgrade_link,
        'upgrade_price': unicode(get_cosmetic_verified_display_price(course)),
        'enrollment_mode': enrollment_mode,
        'enrollment_time': enrollment_time,
        'pacing_type':
        'self_paced' if course.self_paced else 'instructor_paced',
        'upgrade_deadline': upgrade_date,
        'course_key': course.id,
        'course_start': course.start,
        'course_end': course.end,
        'has_staff_access': has_staff_access,
        'forum_roles': forum_roles,
        'partition_groups': user_partitions,
        # TODO: clean up as part of REVO-28 (START)
        'has_non_audit_enrollments': has_non_audit_enrollments,
        # TODO: clean up as part of REVO-28 (END)
    }
Пример #9
0
    def get_verification_context(request, course):
        enrollment = CourseEnrollment.get_enrollment(request.user, course.id)
        show_course_sock = verified_upgrade_link_is_valid(
            enrollment) and get_language() == 'en'
        upgrade_url = verified_upgrade_deadline_link(request.user,
                                                     course=course)
        course_price = get_cosmetic_verified_display_price(course)

        context = {
            'show_course_sock': show_course_sock,
            'course_price': course_price,
            'course_id': course.id,
            'upgrade_url': upgrade_url,
        }

        return context
Пример #10
0
    def get_verification_context(request, course):
        enrollment = CourseEnrollment.get_enrollment(request.user, course.id)
        show_course_sock = verified_upgrade_link_is_valid(enrollment) and get_language() == 'en'
        if show_course_sock:
            upgrade_url = verified_upgrade_deadline_link(request.user, course=course)
            course_price = get_cosmetic_verified_display_price(course)
        else:
            upgrade_url = ''
            course_price = ''

        context = {
            'show_course_sock': show_course_sock,
            'course_price': course_price,
            'course_id': course.id,
            'upgrade_url': upgrade_url,
        }

        return context
Пример #11
0
def get_experiment_user_metadata_context(course, user):
    """
    Return a context dictionary with the keys used by the user_metadata.html.
    """
    enrollment_mode = None
    enrollment_time = None
    enrollment = None
    try:
        enrollment = CourseEnrollment.objects.select_related(
            'course'
        ).get(user_id=user.id, course_id=course.id)
        if enrollment.is_active:
            enrollment_mode = enrollment.mode
            enrollment_time = enrollment.created
    except CourseEnrollment.DoesNotExist:
        pass  # Not enrolled, used the default None values

    upgrade_link, upgrade_date = check_and_get_upgrade_link_and_date(user, enrollment, course)
    has_staff_access = has_staff_access_to_preview_mode(user, course.id)
    forum_roles = []
    if user.is_authenticated:
        forum_roles = list(Role.objects.filter(users=user, course_id=course.id).values_list('name').distinct())

    # get user partition data
    partition_groups = get_all_partitions_for_course(course)
    user_partitions = get_user_partition_groups(course.id, partition_groups, user, 'name')

    return {
        'upgrade_link': upgrade_link,
        'upgrade_price': unicode(get_cosmetic_verified_display_price(course)),
        'enrollment_mode': enrollment_mode,
        'enrollment_time': enrollment_time,
        'pacing_type': 'self_paced' if course.self_paced else 'instructor_paced',
        'upgrade_deadline': upgrade_date,
        'course_key': course.id,
        'course_start': course.start,
        'course_end': course.end,
        'has_staff_access': has_staff_access,
        'forum_roles': forum_roles,
        'partition_groups': user_partitions,
    }
Пример #12
0
def get_experiment_user_metadata_context(course, user):
    """
    Return a context dictionary with the keys used by the user_metadata.html.
    """
    enrollment_mode = None
    enrollment_time = None
    enrollment = None
    try:
        enrollment = CourseEnrollment.objects.select_related('course').get(
            user_id=user.id, course_id=course.id)
        if enrollment.is_active:
            enrollment_mode = enrollment.mode
            enrollment_time = enrollment.created
    except CourseEnrollment.DoesNotExist:
        pass  # Not enrolled, used the default None values

    upgrade_link, upgrade_date = check_and_get_upgrade_link_and_date(
        user, enrollment, course)
    has_staff_access = has_staff_access_to_preview_mode(user, course)
    forum_roles = []
    if user.is_authenticated:
        forum_roles = list(
            Role.objects.filter(
                users=user,
                course_id=course.id).values_list('name').distinct())

    return {
        'upgrade_link': upgrade_link,
        'upgrade_price': unicode(get_cosmetic_verified_display_price(course)),
        'enrollment_mode': enrollment_mode,
        'enrollment_time': enrollment_time,
        'pacing_type':
        'self_paced' if course.self_paced else 'instructor_paced',
        'upgrade_deadline': upgrade_date,
        'course_key': course.id,
        'course_start': course.start,
        'course_end': course.end,
        'has_staff_access': has_staff_access,
        'forum_roles': forum_roles
    }
Пример #13
0
    def get(self, request, course_id):
        """
        Displays the user's Learner Analytics for the specified course.

        Arguments:
            request: HTTP request
            course_id (unicode): course id
        """
        course_key = CourseKey.from_string(course_id)
        if not ENABLE_DASHBOARD_TAB.is_enabled(course_key):
            raise Http404

        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=True)
        course_url_name = default_course_url_name(course.id)
        course_url = reverse(course_url_name,
                             kwargs={'course_id': unicode(course.id)})

        is_verified = CourseEnrollment.is_enrolled_as_verified(
            request.user, course_key)
        has_access = is_verified or request.user.is_staff

        enrollment = CourseEnrollment.get_enrollment(request.user, course_key)

        upgrade_price = None
        upgrade_url = None

        if enrollment and enrollment.upgrade_deadline:
            upgrade_url = EcommerceService().upgrade_url(
                request.user, course_key)
            upgrade_price = get_cosmetic_verified_display_price(course)

        context = {
            'upgrade_price': upgrade_price,
            'upgrade_link': upgrade_url,
            'course': course,
            'course_url': course_url,
            'disable_courseware_js': True,
            'uses_pattern_library': True,
            'is_self_paced': course.self_paced,
            'is_verified': is_verified,
            'has_access': has_access,
        }

        if (has_access):
            grading_policy = course.grading_policy

            (raw_grade_data, answered_percent,
             percent_grade) = self.get_grade_data(
                 request.user, course_key, grading_policy['GRADE_CUTOFFS'])
            raw_schedule_data = self.get_assignments_with_due_date(
                request, course_key)

            grade_data, schedule_data = self.sort_grade_and_schedule_data(
                raw_grade_data, raw_schedule_data)

            # TODO: LEARNER-3854: Fix hacked defaults with real error handling if implementing Learner Analytics.
            try:
                weekly_active_users = self.get_weekly_course_activity_count(
                    course_key)
                week_streak = self.consecutive_weeks_of_course_activity_for_user(
                    request.user.username, course_key)
            except Exception as e:
                logging.exception(e)
                weekly_active_users = 134
                week_streak = 1

            context.update({
                'grading_policy':
                grading_policy,
                'assignment_grades':
                grade_data,
                'answered_percent':
                answered_percent,
                'assignment_schedule':
                schedule_data,
                'assignment_schedule_raw':
                raw_schedule_data,
                'profile_image_urls':
                get_profile_image_urls_for_user(request.user, request),
                'discussion_info':
                self.get_discussion_data(request, course_key),
                'passing_grade':
                math.ceil(100 * course.lowest_passing_grade),
                'percent_grade':
                math.ceil(100 * percent_grade),
                'weekly_active_users':
                weekly_active_users,
                'week_streak':
                week_streak,
            })

        return render_to_response('learner_analytics/dashboard.html', context)
Пример #14
0
    def get(self, request):
        """
        Return the if the course should be upsold in the mobile app, if the user has appropriate permissions.
        """
        if not MOBILE_UPSELL_FLAG.is_enabled():
            return Response({
                'show_upsell': False,
                'upsell_flag': False,
            })

        course_id = request.GET.get('course_id')
        try:
            course_key = CourseKey.from_string(course_id)
        except InvalidKeyError:
            return HttpResponseBadRequest("Missing or invalid course_id")

        course = CourseOverview.get_from_id(course_key)
        if not course.has_started() or course.has_ended():
            return Response({
                'show_upsell': False,
                'upsell_flag': MOBILE_UPSELL_FLAG.is_enabled(),
                'course_running': False,
            })

        user = request.user
        try:
            enrollment = CourseEnrollment.objects.select_related('course').get(
                user_id=user.id, course_id=course.id)
            user_upsell = verified_upgrade_link_is_valid(enrollment)
        except CourseEnrollment.DoesNotExist:
            user_upsell = True

        basket_url = EcommerceService().upgrade_url(user, course.id)
        upgrade_price = six.text_type(
            get_cosmetic_verified_display_price(course))
        could_upsell = bool(user_upsell and basket_url)

        bucket = stable_bucketing_hash_group(MOBILE_UPSELL_EXPERIMENT, 2,
                                             user.username)

        if could_upsell and hasattr(
                request,
                'session') and MOBILE_UPSELL_EXPERIMENT not in request.session:
            properties = {
                'site': request.site.domain,
                'app_label': 'experiments',
                'bucket': bucket,
                'experiment': 'REV-934',
            }
            segment.track(
                user_id=user.id,
                event_name='edx.bi.experiment.user.bucketed',
                properties=properties,
            )

            # Mark that we've recorded this bucketing, so that we don't do it again this session
            request.session[MOBILE_UPSELL_EXPERIMENT] = True

        show_upsell = bool(bucket != 0 and could_upsell)
        if show_upsell:
            return Response({
                'show_upsell': show_upsell,
                'price': upgrade_price,
                'basket_url': basket_url,
            })
        else:
            return Response({
                'show_upsell': show_upsell,
                'upsell_flag': MOBILE_UPSELL_FLAG.is_enabled(),
                'experiment_bucket': bucket,
                'user_upsell': user_upsell,
                'basket_url': basket_url,
            })
Пример #15
0
    def render_to_fragment(self, request, course_id=None, **kwargs):
        """
        Renders the course's home page as a fragment.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user, 'load', course_key)

        # Render the course dates as a fragment
        dates_fragment = CourseDatesFragmentView().render_to_fragment(request, course_id=course_id, **kwargs)

        # Render the full content to enrolled users, as well as to course and global staff.
        # Unenrolled users who are not course or global staff are given only a subset.
        enrollment = CourseEnrollment.get_enrollment(request.user, course_key)
        user_access = {
            'is_anonymous': request.user.is_anonymous(),
            'is_enrolled': enrollment is not None,
            'is_staff': has_access(request.user, 'staff', course_key),
        }
        if user_access['is_enrolled'] or user_access['is_staff']:
            outline_fragment = CourseOutlineFragmentView().render_to_fragment(request, course_id=course_id, **kwargs)
            if LATEST_UPDATE_FLAG.is_enabled(course_key):
                update_message_fragment = LatestUpdateFragmentView().render_to_fragment(
                    request, course_id=course_id, **kwargs
                )
            else:
                update_message_fragment = WelcomeMessageFragmentView().render_to_fragment(
                    request, course_id=course_id, **kwargs
                )
            course_sock_fragment = CourseSockFragmentView().render_to_fragment(request, course=course, **kwargs)
            has_visited_course, resume_course_url = self._get_resume_course_info(request, course_id)
        else:
            # Redirect the user to the dashboard if they are not enrolled and
            # this is a course that does not support direct enrollment.
            if not can_self_enroll_in_course(course_key):
                raise CourseAccessRedirect(reverse('dashboard'))

            # Set all the fragments
            outline_fragment = None
            update_message_fragment = None
            course_sock_fragment = None
            has_visited_course = None
            resume_course_url = None

        # Get the handouts
        handouts_html = self._get_course_handouts(request, course)

        # Get the course tools enabled for this user and course
        course_tools = CourseToolsPluginManager.get_enabled_course_tools(request, course_key)

        # Check if the user can access the course goal functionality
        has_goal_permission = has_course_goal_permission(request, course_id, user_access)

        # Grab the current course goal and the acceptable course goal keys mapped to translated values
        current_goal = get_course_goal(request.user, course_key)
        goal_options = get_course_goal_options()

        # Get the course goals api endpoint
        goal_api_url = get_goal_api_url(request)

        # Grab the course home messages fragment to render any relevant django messages
        course_home_message_fragment = CourseHomeMessageFragmentView().render_to_fragment(
            request, course_id=course_id, user_access=user_access, **kwargs
        )

        # Get info for upgrade messaging
        upgrade_price = None
        upgrade_url = None

        # TODO Add switch to control deployment
        if SHOW_UPGRADE_MSG_ON_COURSE_HOME.is_enabled(course_key) and enrollment and enrollment.upgrade_deadline:
            upgrade_url = EcommerceService().upgrade_url(request.user, course_key)
            upgrade_price = get_cosmetic_verified_display_price(course)

        # Render the course home fragment
        context = {
            'request': request,
            'csrf': csrf(request)['csrf_token'],
            'course': course,
            'course_key': course_key,
            'outline_fragment': outline_fragment,
            'handouts_html': handouts_html,
            'course_home_message_fragment': course_home_message_fragment,
            'has_visited_course': has_visited_course,
            'resume_course_url': resume_course_url,
            'course_tools': course_tools,
            'dates_fragment': dates_fragment,
            'username': request.user.username,
            'goal_api_url': goal_api_url,
            'has_goal_permission': has_goal_permission,
            'goal_options': goal_options,
            'current_goal': current_goal,
            'update_message_fragment': update_message_fragment,
            'course_sock_fragment': course_sock_fragment,
            'disable_courseware_js': True,
            'uses_pattern_library': True,
            'upgrade_price': upgrade_price,
            'upgrade_url': upgrade_url,
        }
        html = render_to_string('course_experience/course-home-fragment.html', context)
        return Fragment(html)
Пример #16
0
def get_deprecated_experiment_user_metadata_context(course, user):
    """
    Return a context dictionary with the keys used by the user_metadata.html. This is deprecated and will be removed
    once we have confirmed that its replacement functions as intended.
    """
    enrollment_mode = None
    enrollment_time = None
    enrollment = None
    # TODO: clean up as part of REVO-28 (START)
    has_non_audit_enrollments = None
    # TODO: clean up as part of REVO-28 (END)
    # TODO: clean up as part of REVEM-199 (START)
    program_key = None
    # TODO: clean up as part of REVEM-199 (END)
    try:
        # TODO: clean up as part of REVO-28 (START)
        user_enrollments = CourseEnrollment.objects.select_related('course').filter(user_id=user.id)
        audit_enrollments = user_enrollments.filter(mode='audit')
        has_non_audit_enrollments = (len(audit_enrollments) != len(user_enrollments))
        # TODO: clean up as part of REVO-28 (END)
        # TODO: clean up as part of REVEM-199 (START)
        if PROGRAM_INFO_FLAG.is_enabled():
            programs = get_programs(course=course.id)
            if programs:
                # A course can be in multiple programs, but we're just grabbing the first one
                program = programs[0]
                complete_enrollment = False
                has_courses_left_to_purchase = False
                total_courses = None
                courses = program.get('courses')
                courses_left_to_purchase_price = None
                courses_left_to_purchase_url = None
                program_uuid = program.get('uuid')
                status = None
                is_eligible_for_one_click_purchase = None
                if courses is not None:
                    total_courses = len(courses)
                    complete_enrollment = is_enrolled_in_all_courses(courses, user_enrollments)
                    status = program.get('status')
                    is_eligible_for_one_click_purchase = program.get('is_program_eligible_for_one_click_purchase')
                    # Get the price and purchase URL of the program courses the user has yet to purchase. Say a
                    # program has 3 courses (A, B and C), and the user previously purchased a certificate for A.
                    # The user is enrolled in audit mode for B. The "left to purchase price" should be the price of
                    # B+C.
                    non_audit_enrollments = [en for en in user_enrollments if en not in
                                             audit_enrollments]
                    courses_left_to_purchase = get_unenrolled_courses(courses, non_audit_enrollments)
                    if courses_left_to_purchase:
                        has_courses_left_to_purchase = True
                        if is_eligible_for_one_click_purchase:
                            courses_left_to_purchase_price, courses_left_to_purchase_skus = \
                                get_program_price_and_skus(courses_left_to_purchase)
                            if courses_left_to_purchase_skus:
                                courses_left_to_purchase_url = EcommerceService().get_checkout_page_url(
                                    *courses_left_to_purchase_skus, program_uuid=program_uuid)

                program_key = {
                    'uuid': program_uuid,
                    'title': program.get('title'),
                    'marketing_url': program.get('marketing_url'),
                    'status': status,
                    'is_eligible_for_one_click_purchase': is_eligible_for_one_click_purchase,
                    'total_courses': total_courses,
                    'complete_enrollment': complete_enrollment,
                    'has_courses_left_to_purchase': has_courses_left_to_purchase,
                    'courses_left_to_purchase_price': courses_left_to_purchase_price,
                    'courses_left_to_purchase_url': courses_left_to_purchase_url,
                }
        # TODO: clean up as part of REVEM-199 (END)
        enrollment = CourseEnrollment.objects.select_related(
            'course'
        ).get(user_id=user.id, course_id=course.id)
        if enrollment.is_active:
            enrollment_mode = enrollment.mode
            enrollment_time = enrollment.created
    except CourseEnrollment.DoesNotExist:
        pass  # Not enrolled, used the default None values

    # upgrade_link and upgrade_date should be None if user has passed their dynamic pacing deadline.
    upgrade_link, upgrade_date = check_and_get_upgrade_link_and_date(user, enrollment, course)
    has_staff_access = has_staff_access_to_preview_mode(user, course.id)
    forum_roles = []
    if user.is_authenticated:
        forum_roles = list(Role.objects.filter(users=user, course_id=course.id).values_list('name').distinct())

    # get user partition data
    if user.is_authenticated():
        partition_groups = get_all_partitions_for_course(course)
        user_partitions = get_user_partition_groups(course.id, partition_groups, user, 'name')
    else:
        user_partitions = {}

    return {
        'upgrade_link': upgrade_link,
        'upgrade_price': six.text_type(get_cosmetic_verified_display_price(course)),
        'enrollment_mode': enrollment_mode,
        'enrollment_time': enrollment_time,
        'pacing_type': 'self_paced' if course.self_paced else 'instructor_paced',
        'upgrade_deadline': upgrade_date,
        'audit_access_deadline': get_audit_access_expiration(user, course),
        'course_key': course.id,
        'course_start': course.start,
        'course_end': course.end,
        'has_staff_access': has_staff_access,
        'forum_roles': forum_roles,
        'partition_groups': user_partitions,
        # TODO: clean up as part of REVO-28 (START)
        'has_non_audit_enrollments': has_non_audit_enrollments,
        # TODO: clean up as part of REVO-28 (END)
        # TODO: clean up as part of REVEM-199 (START)
        'program_key_fields': program_key,
        # TODO: clean up as part of REVEM-199 (END)
    }
Пример #17
0
def get_experiment_user_metadata_context(course, user):
    """
    Return a context dictionary with the keys used by the user_metadata.html.
    """
    enrollment_mode = None
    enrollment_time = None
    enrollment = None
    # TODO: clean up as part of REVO-28 (START)
    has_non_audit_enrollments = None
    # TODO: clean up as part of REVO-28 (END)
    # TODO: clean up as part of REVEM-106 (START)
    program_key = None
    # TODO: clean up as part of REVEM-106 (END)
    try:
        # TODO: clean up as part of REVO-28 (START)
        user_enrollments = CourseEnrollment.objects.select_related(
            'course').filter(user_id=user.id)
        audit_enrollments = user_enrollments.filter(mode='audit')
        has_non_audit_enrollments = (len(audit_enrollments) !=
                                     len(user_enrollments))
        # TODO: clean up as part of REVO-28 (END)
        enrollment = CourseEnrollment.objects.select_related('course').get(
            user_id=user.id, course_id=course.id)
        if enrollment.is_active:
            enrollment_mode = enrollment.mode
            enrollment_time = enrollment.created

            # TODO: clean up as part of REVEM-106 (START)
            # get program data for this course
            request = get_current_request()
            if request:
                enrollment_list = [enrollment]
                meter = ProgramProgressMeter(request.site,
                                             user,
                                             enrollments=enrollment_list)
                if meter.engaged_programs and meter.engaged_programs[0]:
                    org_name = None
                    courses_not_started = 0
                    courses_in_progress = 0
                    courses_completed = 0
                    program_data = meter.engaged_programs[0]
                    program_data = ProgramDataExtender(
                        program_data, user, mobile_only=False).extend()
                    program_orgs = program_data.get(
                        'credit_backing_organizations')
                    if program_orgs and program_orgs[0]:
                        org = program_orgs[0]
                        org_name = org.get('name')
                    if meter.progress() and meter.progress()[0]:
                        progress = meter.progress()[0]
                        courses_not_started = progress.get('not_started')
                        courses_in_progress = progress.get('in_progress')
                        courses_completed = progress.get('completed')
                    program_key = {
                        'uuid': program_data.get('uuid'),
                        'title': program_data.get('title'),
                        'marketing_url': program_data.get('marketing_url'),
                        'org_name': org_name,
                        'courses_not_started': courses_not_started,
                        'courses_in_progress': courses_in_progress,
                        'courses_completed': courses_completed,
                    }
            # TODO: clean up as part of REVEM-106 (END)
    except CourseEnrollment.DoesNotExist:
        pass  # Not enrolled, used the default None values

    # upgrade_link and upgrade_date should be None if user has passed their dynamic pacing deadline.
    upgrade_link, upgrade_date = check_and_get_upgrade_link_and_date(
        user, enrollment, course)
    has_staff_access = has_staff_access_to_preview_mode(user, course.id)
    forum_roles = []
    if user.is_authenticated:
        forum_roles = list(
            Role.objects.filter(
                users=user,
                course_id=course.id).values_list('name').distinct())

    # get user partition data
    if user.is_authenticated():
        partition_groups = get_all_partitions_for_course(course)
        user_partitions = get_user_partition_groups(course.id,
                                                    partition_groups, user,
                                                    'name')
    else:
        user_partitions = {}

    return {
        'upgrade_link': upgrade_link,
        'upgrade_price': unicode(get_cosmetic_verified_display_price(course)),
        'enrollment_mode': enrollment_mode,
        'enrollment_time': enrollment_time,
        'pacing_type':
        'self_paced' if course.self_paced else 'instructor_paced',
        'upgrade_deadline': upgrade_date,
        'course_key': course.id,
        'course_start': course.start,
        'course_end': course.end,
        'has_staff_access': has_staff_access,
        'forum_roles': forum_roles,
        'partition_groups': user_partitions,
        # TODO: clean up as part of REVO-28 (START)
        'has_non_audit_enrollments': has_non_audit_enrollments,
        # TODO: clean up as part of REVO-28 (END)
        # TODO: clean up as part of REVEM-106 (START)
        'program_key_fields': program_key,
        # TODO: clean up as part of REVEM-106 (END)
    }
Пример #18
0
    def get(self, request, course_id):
        """
        Displays the user's Learner Analytics for the specified course.

        Arguments:
            request: HTTP request
            course_id (unicode): course id
        """
        course_key = CourseKey.from_string(course_id)
        if not ENABLE_DASHBOARD_TAB.is_enabled(course_key):
            raise Http404

        course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=True)
        course_url_name = default_course_url_name(course.id)
        course_url = reverse(course_url_name, kwargs={'course_id': unicode(course.id)})

        is_verified = CourseEnrollment.is_enrolled_as_verified(request.user, course_key)
        has_access = is_verified or request.user.is_staff

        enrollment = CourseEnrollment.get_enrollment(request.user, course_key)

        upgrade_price = None
        upgrade_url = None

        if enrollment and enrollment.upgrade_deadline:
            upgrade_url = EcommerceService().upgrade_url(request.user, course_key)
            upgrade_price = get_cosmetic_verified_display_price(course)

        context = {
            'upgrade_price': upgrade_price,
            'upgrade_link': upgrade_url,
            'course': course,
            'course_url': course_url,
            'disable_courseware_js': True,
            'uses_pattern_library': True,
            'is_self_paced': course.self_paced,
            'is_verified': is_verified,
            'has_access': has_access,
        }

        if (has_access):
            grading_policy = course.grading_policy

            (raw_grade_data, answered_percent, percent_grade) = self.get_grade_data(request.user, course_key, grading_policy['GRADE_CUTOFFS'])
            raw_schedule_data = self.get_assignments_with_due_date(request, course_key)

            grade_data, schedule_data = self.sort_grade_and_schedule_data(raw_grade_data, raw_schedule_data)

            # TODO: LEARNER-3854: Fix hacked defaults with real error handling if implementing Learner Analytics.
            try:
                weekly_active_users = self.get_weekly_course_activity_count(course_key)
                week_streak = self.consecutive_weeks_of_course_activity_for_user(
                    request.user.username, course_key
                )
            except Exception as e:
                logging.exception(e)
                weekly_active_users = 134
                week_streak = 1

            context.update({
                'grading_policy': grading_policy,
                'assignment_grades': grade_data,
                'answered_percent': answered_percent,
                'assignment_schedule': schedule_data,
                'assignment_schedule_raw': raw_schedule_data,
                'profile_image_urls': get_profile_image_urls_for_user(request.user, request),
                'discussion_info': self.get_discussion_data(request, course_key),
                'passing_grade': math.ceil(100 * course.lowest_passing_grade),
                'percent_grade': math.ceil(100 * percent_grade),
                'weekly_active_users': weekly_active_users,
                'week_streak': week_streak,
            })

        return render_to_response('learner_analytics/dashboard.html', context)
Пример #19
0
    def render_to_fragment(self, request, course_id=None, **kwargs):
        """
        Renders the course's home page as a fragment.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user, 'load', course_key)

        # Render the course dates as a fragment
        dates_fragment = CourseDatesFragmentView().render_to_fragment(request, course_id=course_id, **kwargs)

        # Render the full content to enrolled users, as well as to course and global staff.
        # Unenrolled users who are not course or global staff are given only a subset.
        enrollment = CourseEnrollment.get_enrollment(request.user, course_key)
        user_access = {
            'is_anonymous': request.user.is_anonymous(),
            'is_enrolled': enrollment is not None,
            'is_staff': has_access(request.user, 'staff', course_key),
        }
        if user_access['is_enrolled'] or user_access['is_staff']:
            outline_fragment = CourseOutlineFragmentView().render_to_fragment(request, course_id=course_id, **kwargs)
            if LATEST_UPDATE_FLAG.is_enabled(course_key):
                update_message_fragment = LatestUpdateFragmentView().render_to_fragment(
                    request, course_id=course_id, **kwargs
                )
            else:
                update_message_fragment = WelcomeMessageFragmentView().render_to_fragment(
                    request, course_id=course_id, **kwargs
                )
            course_sock_fragment = CourseSockFragmentView().render_to_fragment(request, course=course, **kwargs)
            has_visited_course, resume_course_url = self._get_resume_course_info(request, course_id)
        else:
            # Redirect the user to the dashboard if they are not enrolled and
            # this is a course that does not support direct enrollment.
            if not can_self_enroll_in_course(course_key):
                raise CourseAccessRedirect(reverse('dashboard'))

            # Set all the fragments
            outline_fragment = None
            update_message_fragment = None
            course_sock_fragment = None
            has_visited_course = None
            resume_course_url = None

        # Get the handouts
        handouts_html = self._get_course_handouts(request, course)

        # Get the course tools enabled for this user and course
        course_tools = CourseToolsPluginManager.get_enabled_course_tools(request, course_key)

        # Check if the user can access the course goal functionality
        has_goal_permission = has_course_goal_permission(request, course_id, user_access)

        # Grab the current course goal and the acceptable course goal keys mapped to translated values
        current_goal = get_course_goal(request.user, course_key)
        goal_options = get_course_goal_options()

        # Get the course goals api endpoint
        goal_api_url = get_goal_api_url(request)

        # Grab the course home messages fragment to render any relevant django messages
        course_home_message_fragment = CourseHomeMessageFragmentView().render_to_fragment(
            request, course_id=course_id, user_access=user_access, **kwargs
        )

        # Get info for upgrade messaging
        upgrade_price = None
        upgrade_url = None

        # TODO Add switch to control deployment
        if SHOW_UPGRADE_MSG_ON_COURSE_HOME.is_enabled(course_key) and enrollment and enrollment.upgrade_deadline:
            upgrade_url = EcommerceService().upgrade_url(request.user, course_key)
            upgrade_price = get_cosmetic_verified_display_price(course)

        # Render the course home fragment
        context = {
            'request': request,
            'csrf': csrf(request)['csrf_token'],
            'course': course,
            'course_key': course_key,
            'outline_fragment': outline_fragment,
            'handouts_html': handouts_html,
            'course_home_message_fragment': course_home_message_fragment,
            'has_visited_course': has_visited_course,
            'resume_course_url': resume_course_url,
            'course_tools': course_tools,
            'dates_fragment': dates_fragment,
            'username': request.user.username,
            'goal_api_url': goal_api_url,
            'has_goal_permission': has_goal_permission,
            'goal_options': goal_options,
            'current_goal': current_goal,
            'update_message_fragment': update_message_fragment,
            'course_sock_fragment': course_sock_fragment,
            'disable_courseware_js': True,
            'uses_pattern_library': True,
            'upgrade_price': upgrade_price,
            'upgrade_url': upgrade_url,
        }
        html = render_to_string('course_experience/course-home-fragment.html', context)
        return Fragment(html)
Пример #20
0
def get_experiment_user_metadata_context(course, user):
    """
    Return a context dictionary with the keys used by the user_metadata.html.
    """
    enrollment_mode = None
    enrollment_time = None
    enrollment = None
    # TODO: clean up as part of REVO-28 (START)
    has_non_audit_enrollments = None
    # TODO: clean up as part of REVO-28 (END)

    # TODO: clean up as part of REVEM-199 (START)
    program_key = None
    # TODO: clean up as part of REVEM-199 (END)
    try:
        # TODO: clean up as part of REVO-28 (START)
        user_enrollments = CourseEnrollment.objects.select_related(
            'course').filter(user_id=user.id)
        audit_enrollments = user_enrollments.filter(mode='audit')
        has_non_audit_enrollments = (len(audit_enrollments) !=
                                     len(user_enrollments))
        # TODO: clean up as part of REVO-28 (END)
        enrollment = CourseEnrollment.objects.select_related('course').get(
            user_id=user.id, course_id=course.id)
        if enrollment.is_active:
            enrollment_mode = enrollment.mode
            enrollment_time = enrollment.created

            # TODO: clean up as part of REVEM-199 (START)
            if PROGRAM_INFO_FLAG.is_enabled():
                programs = get_programs(course=course.id)
                if programs:
                    # A course can be in multiple programs, but we're just grabbing the first one
                    program = programs[0]
                    complete_enrollment = False
                    total_courses = None
                    courses = program.get('courses')
                    if courses is not None:
                        total_courses = len(courses)
                        complete_enrollment = is_enrolled_in_all_courses_in_program(
                            courses, user_enrollments)

                    program_key = {
                        'uuid': program.get('uuid'),
                        'title': program.get('title'),
                        'marketing_url': program.get('marketing_url'),
                        'total_courses': total_courses,
                        'complete_enrollment': complete_enrollment,
                    }
            # TODO: clean up as part of REVEM-199 (END)
    except CourseEnrollment.DoesNotExist:
        pass  # Not enrolled, used the default None values

    # upgrade_link and upgrade_date should be None if user has passed their dynamic pacing deadline.
    upgrade_link, upgrade_date = check_and_get_upgrade_link_and_date(
        user, enrollment, course)
    has_staff_access = has_staff_access_to_preview_mode(user, course.id)
    forum_roles = []
    if user.is_authenticated:
        forum_roles = list(
            Role.objects.filter(
                users=user,
                course_id=course.id).values_list('name').distinct())

    # get user partition data
    if user.is_authenticated():
        partition_groups = get_all_partitions_for_course(course)
        user_partitions = get_user_partition_groups(course.id,
                                                    partition_groups, user,
                                                    'name')
    else:
        user_partitions = {}

    return {
        'upgrade_link': upgrade_link,
        'upgrade_price': unicode(get_cosmetic_verified_display_price(course)),
        'enrollment_mode': enrollment_mode,
        'enrollment_time': enrollment_time,
        'pacing_type':
        'self_paced' if course.self_paced else 'instructor_paced',
        'upgrade_deadline': upgrade_date,
        'course_key': course.id,
        'course_start': course.start,
        'course_end': course.end,
        'has_staff_access': has_staff_access,
        'forum_roles': forum_roles,
        'partition_groups': user_partitions,
        # TODO: clean up as part of REVO-28 (START)
        'has_non_audit_enrollments': has_non_audit_enrollments,
        # TODO: clean up as part of REVO-28 (END)
        # TODO: clean up as part of REVEM-199 (START)
        'program_key_fields': program_key,
        # TODO: clean up as part of REVEM-199 (END)
    }