示例#1
0
    def test_get_experiment_user_metadata_context(self):
        course = CourseFactory.create(start=now() - timedelta(days=30), pacing_type="instructor_paced", course_duration=None, upgrade_price='Free',  # lint-amnesty, pylint: disable=line-too-long
                                      upgrade_link=None, enrollment_mode=None, audit_access_deadline=None, program_key_fields=None, schedule_start=None,  # lint-amnesty, pylint: disable=line-too-long
                                      enrollment_time=None, dynamic_upgrade_deadline=None, course_upgrade_deadline=None, course_key_fields={'org': 'org.0', 'course': 'course_0', 'run': 'Run_0'})  # lint-amnesty, pylint: disable=line-too-long
        user = UserFactory()
        context = get_experiment_user_metadata_context(course, user)
        CourseEnrollmentFactory(course_id=course.id, user=user)

        user_metadata_expected_result = {'username': user.username,
                                         'user_id': user.id,
                                         'course_id': course.id,
                                         'enrollment_mode': course.enrollment_mode,
                                         'upgrade_link': course.upgrade_link,
                                         'upgrade_price': course.upgrade_price,
                                         'audit_access_deadline': course.audit_access_deadline,
                                         'course_duration': course.course_duration,
                                         'pacing_type': course.pacing_type,
                                         'has_staff_access': False,
                                         'forum_roles': [],
                                         'partition_groups': {},
                                         'has_non_audit_enrollments': False,
                                         'program_key_fields': course.program_key_fields,
                                         'email': user.email,
                                         'schedule_start': course.schedule_start,
                                         'enrollment_time': course.enrollment_time,
                                         'course_start': course.start,
                                         'course_end': course.end,
                                         'dynamic_upgrade_deadline': course.dynamic_upgrade_deadline,
                                         'course_upgrade_deadline': course.course_upgrade_deadline,
                                         'course_key_fields': course.course_key_fields}

        user_metadata = context.get('user_metadata')

        self.assertTrue(user_metadata, user_metadata_expected_result)
示例#2
0
    def get(self, request, course_id=None, username=None):
        """ Return user-metadata for the given course and user """
        try:
            user = get_user_by_username_or_email(username)
        except User.DoesNotExist:
            # Note: this will only be seen by staff, for administrative de-bugging purposes
            message = "Provided user is not found"
            return JsonResponse({'message': message}, status=404)

        try:
            course = courses.get_course_by_id(CourseKey.from_string(course_id))
        except Http404:
            message = "Provided course is not found"
            return JsonResponse({'message': message}, status=404)

        context = get_experiment_user_metadata_context(course, user)
        user_metadata = context.get('user_metadata')
        return JsonResponse(user_metadata)
示例#3
0
    def test_get_experiment_user_metadata_context(self):
        course = CourseFactory.create(start=now() - timedelta(days=30))
        user = UserFactory()
        enrollment = CourseEnrollmentFactory(course_id=course.id, user=user)
        context = get_experiment_user_metadata_context(course, user)

        user_metadata_expected_result = {
            'username': user.username,
            'user_id': user.id,
            'course_id': str(course.id),
            'course_display_name': course.display_name_with_default,
            'enrollment_mode': enrollment.mode,
            'upgrade_link': None,
            'upgrade_price': 'Free',
            'audit_access_deadline': None,
            'course_duration': None,
            'pacing_type': 'instructor_paced',
            'has_staff_access': False,
            'forum_roles': [('Student', )],
            'partition_groups': {
                'Enrollment Track Groups': Group(id=1, name='Audit')
            },
            'has_non_audit_enrollments': False,
            'program_key_fields': None,
            'email': user.email,
            'schedule_start': enrollment.schedule.start_date.isoformat(),
            'enrollment_time': enrollment.created.isoformat(),
            'course_start': course.start.isoformat(),
            'course_end': course.end,
            'dynamic_upgrade_deadline': None,
            'course_upgrade_deadline': None,
            'course_key_fields': {
                'org': course.id.org,
                'course': course.id.course,
                'run': course.id.run,
            }
        }

        user_metadata = context.get('user_metadata')

        assert user_metadata == user_metadata_expected_result
示例#4
0
def _create_discussion_board_context(request, base_context, thread=None):
    """
    Returns the template context for rendering the discussion board.
    """
    context = base_context.copy()
    course = context['course']
    course_key = course.id
    thread_id = thread.id if thread else None
    discussion_id = thread.commentable_id if thread else None
    course_settings = context['course_settings']
    user = context['user']
    cc_user = cc.User.from_django_user(user)
    user_info = context['user_info']
    if thread:

        # Since we're in page render mode, and the discussions UI will request the thread list itself,
        # we need only return the thread information for this one.
        threads = [thread.to_dict()]

        for thread in threads:
            # patch for backward compatibility with comments service
            if "pinned" not in thread:
                thread["pinned"] = False
        thread_pages = 1
        root_url = reverse('forum_form_discussion', args=[unicode(course.id)])
    else:
        threads, query_params = get_threads(request, course, user_info)   # This might process a search query
        thread_pages = query_params['num_pages']
        root_url = request.path
    is_staff = has_permission(user, 'openclose_thread', course.id)
    threads = [utils.prepare_content(thread, course_key, is_staff) for thread in threads]

    with function_trace("get_metadata_for_threads"):
        annotated_content_info = utils.get_metadata_for_threads(course_key, threads, user, user_info)

    with function_trace("add_courseware_context"):
        add_courseware_context(threads, course, user)

    with function_trace("get_cohort_info"):
        course_discussion_settings = get_course_discussion_settings(course_key)
        user_group_id = get_group_id_for_user(user, course_discussion_settings)

    context.update({
        'root_url': root_url,
        'discussion_id': discussion_id,
        'thread_id': thread_id,
        'threads': threads,
        'thread_pages': thread_pages,
        'annotated_content_info': annotated_content_info,
        'is_moderator': has_permission(user, "see_all_cohorts", course_key),
        'groups': course_settings["groups"],  # still needed to render _thread_list_template
        'user_group_id': user_group_id,  # read from container in NewPostView
        'sort_preference': cc_user.default_sort_key,
        'category_map': course_settings["category_map"],
        'course_settings': course_settings,
        'is_commentable_divided': is_commentable_divided(course_key, discussion_id, course_discussion_settings),
        # If the default topic id is None the front-end code will look for a topic that contains "General"
        'discussion_default_topic_id': _get_discussion_default_topic_id(course),
    })
    context.update(
        get_experiment_user_metadata_context(
            course,
            user,
        )
    )
    return context
示例#5
0
    def _create_courseware_context(self, request):
        """
        Returns and creates the rendering context for the courseware.
        Also returns the table of contents for the courseware.
        """
        course_url_name = default_course_url_name(self.course.id)
        course_url = reverse(course_url_name,
                             kwargs={'course_id': unicode(self.course.id)})

        courseware_context = {
            'csrf':
            csrf(self.request)['csrf_token'],
            'course':
            self.course,
            'course_url':
            course_url,
            'chapter':
            self.chapter,
            'section':
            self.section,
            'init':
            '',
            'fragment':
            Fragment(),
            'staff_access':
            self.is_staff,
            'masquerade':
            self.masquerade,
            'supports_preview_menu':
            True,
            'studio_url':
            get_studio_url(self.course, 'course'),
            'xqa_server':
            settings.FEATURES.get('XQA_SERVER', "http://your_xqa_server.com"),
            'bookmarks_api_url':
            reverse('bookmarks'),
            'language_preference':
            self._get_language_preference(),
            'disable_optimizely':
            not WaffleSwitchNamespace('RET').is_enabled(
                'enable_optimizely_in_courseware'),
            'section_title':
            None,
            'sequence_title':
            None,
            'disable_accordion':
            COURSE_OUTLINE_PAGE_FLAG.is_enabled(self.course.id),
        }
        courseware_context.update(
            get_experiment_user_metadata_context(
                self.course,
                self.effective_user,
            ))
        table_of_contents = toc_for_course(
            self.effective_user,
            self.request,
            self.course,
            self.chapter_url_name,
            self.section_url_name,
            self.field_data_cache,
        )
        courseware_context['accordion'] = render_accordion(
            self.request,
            self.course,
            table_of_contents['chapters'],
        )

        courseware_context['course_sock_fragment'] = CourseSockFragmentView(
        ).render_to_fragment(request, course=self.course)

        # entrance exam data
        self._add_entrance_exam_to_context(courseware_context)

        if self.section:
            # chromeless data
            if self.section.chrome:
                chrome = [
                    s.strip() for s in self.section.chrome.lower().split(",")
                ]
                if 'accordion' not in chrome:
                    courseware_context['disable_accordion'] = True
                if 'tabs' not in chrome:
                    courseware_context['disable_tabs'] = True

            # default tab
            if self.section.default_tab:
                courseware_context['default_tab'] = self.section.default_tab

            # section data
            courseware_context[
                'section_title'] = self.section.display_name_with_default
            section_context = self._create_section_context(
                table_of_contents['previous_of_active_section'],
                table_of_contents['next_of_active_section'],
            )

            courseware_context['fragment'] = self.section.render(
                self.view, section_context)

            if self.section.position and self.section.has_children:
                self._add_sequence_title_to_context(courseware_context)

        return courseware_context
示例#6
0
def student_dashboard(request):
    """
    Provides the LMS dashboard view

    TODO: This is lms specific and does not belong in common code.
    Note:
        To load the all courses set course_limit=None as parameter in GET. If its not None then default course
        limit will be used  that is set in configuration
    Arguments:
        request: The request object.

    Returns:
        The dashboard response.

    """
    user = request.user

    #Added by Mahendra
    if request.is_ajax():
        if request.method == 'GET' :
            if user.is_authenticated:
                if request.GET.get('disclaimer'):
                    log.info(u'disclaimer %s', request.GET.get('disclaimer'))
                    usr = request.user.id
                    cid = request.GET.get('cid')
                    disclaimer = disclaimer_agreement_status(course_id=cid, user_id=usr, status='1')
                    disclaimer.save()
                else:
                    usr = request.user.id
                    cid = request.GET.get('cid')
                    view_counter = user_view_counter.objects.filter(course_id=cid, user=usr)
                    if view_counter :
                        update_counter = user_view_counter.objects.filter(
                            course_id=cid,
                            user=usr
                        ).update(counter = F('counter')+1)
                    else:
                        countr = user_view_counter(user_id=usr, course_id=cid,counter=1)
                        countr.save()

    if not UserProfile.objects.filter(user=user).exists():
        return redirect(reverse('account_settings'))

    platform_name = configuration_helpers.get_value("platform_name", settings.PLATFORM_NAME)

    enable_verified_certificates = configuration_helpers.get_value(
        'ENABLE_VERIFIED_CERTIFICATES',
        settings.FEATURES.get('ENABLE_VERIFIED_CERTIFICATES')
    )
    display_course_modes_on_dashboard = configuration_helpers.get_value(
        'DISPLAY_COURSE_MODES_ON_DASHBOARD',
        settings.FEATURES.get('DISPLAY_COURSE_MODES_ON_DASHBOARD', True)
    )
    activation_email_support_link = configuration_helpers.get_value(
        'ACTIVATION_EMAIL_SUPPORT_LINK', settings.ACTIVATION_EMAIL_SUPPORT_LINK
    ) or settings.SUPPORT_SITE_LINK
    hide_dashboard_courses_until_activated = configuration_helpers.get_value(
        'HIDE_DASHBOARD_COURSES_UNTIL_ACTIVATED',
        settings.FEATURES.get('HIDE_DASHBOARD_COURSES_UNTIL_ACTIVATED', False)
    )
    empty_dashboard_message = configuration_helpers.get_value(
        'EMPTY_DASHBOARD_MESSAGE', None
    )

    disable_course_limit = request and 'course_limit' in request.GET
    course_limit = get_dashboard_course_limit() if not disable_course_limit else None

    # Get the org whitelist or the org blacklist for the current site
    site_org_whitelist, site_org_blacklist = get_org_black_and_whitelist_for_site()
    course_enrollments = list(get_course_enrollments(user, site_org_whitelist, site_org_blacklist, course_limit))

    #Added by dev below code to display enrolled courses in course start date order
    from lms.djangoapps.course_extrainfo.models import course_extrainfo

    new_enrollments = []
    #log.info('course_enrollments--> %s', course_enrollments)
    for enrollment in course_enrollments:
        new_enrollments.append(enrollment.course_overview.id)

    get_type_courses = course_extrainfo.objects.filter(course_id__in=new_enrollments,course_type=1)

    course_ids = []
    for course in get_type_courses:
        course_ids.append(course.course_id)

    courseslist = CourseOverview.objects.filter(pk__in=course_ids).order_by('-start')

    get_type_lectures = course_extrainfo.objects.filter(course_id__in=new_enrollments,course_type=2)

    lecture_ids = []
    for lecture in get_type_lectures:
        lecture_ids.append(lecture.course_id)

    lectureslist = CourseOverview.objects.filter(pk__in=lecture_ids).order_by('-start')
    #code ends here

    # Get the entitlements for the user and a mapping to all available sessions for that entitlement
    # If an entitlement has no available sessions, pass through a mock course overview object
    (course_entitlements,
     course_entitlement_available_sessions,
     unfulfilled_entitlement_pseudo_sessions) = get_filtered_course_entitlements(
        user,
        site_org_whitelist,
        site_org_blacklist
    )

    # Record how many courses there are so that we can get a better
    # understanding of usage patterns on prod.
    monitoring_utils.accumulate('num_courses', len(course_enrollments))

    # Sort the enrollment pairs by the enrollment date
    course_enrollments.sort(key=lambda x: x.created, reverse=True)

    # Retrieve the course modes for each course
    enrolled_course_ids = [enrollment.course_id for enrollment in course_enrollments]
    __, unexpired_course_modes = CourseMode.all_and_unexpired_modes_for_courses(enrolled_course_ids)
    course_modes_by_course = {
        course_id: {
            mode.slug: mode
            for mode in modes
        }
        for course_id, modes in iteritems(unexpired_course_modes)
    }

    # Check to see if the student has recently enrolled in a course.
    # If so, display a notification message confirming the enrollment.
    enrollment_message = _create_recent_enrollment_message(
        course_enrollments, course_modes_by_course
    )
    course_optouts = Optout.objects.filter(user=user).values_list('course_id', flat=True)

    # Display activation message
    activate_account_message = ''
    if not user.is_active:
        activate_account_message = Text(_(
            "Check your {email_start}{email}{email_end} inbox for an account activation link from {platform_name}. "
            "If you need help, contact {link_start}{platform_name} Support{link_end}."
        )).format(
            platform_name=platform_name,
            email_start=HTML("<strong>"),
            email_end=HTML("</strong>"),
            email=user.email,
            link_start=HTML("<a target='_blank' href='{activation_email_support_link}'>").format(
                activation_email_support_link=activation_email_support_link,
            ),
            link_end=HTML("</a>"),
        )

    enterprise_message = get_dashboard_consent_notification(request, user, course_enrollments)

    # Display a message guiding the user to their Enterprise's Learner Portal if enabled
    enterprise_learner_portal_enabled_message = get_enterprise_learner_portal_enabled_message(request)

    recovery_email_message = recovery_email_activation_message = None
    if is_secondary_email_feature_enabled():
        try:
            pending_email = PendingSecondaryEmailChange.objects.get(user=user)
        except PendingSecondaryEmailChange.DoesNotExist:
            try:
                account_recovery_obj = AccountRecovery.objects.get(user=user)
            except AccountRecovery.DoesNotExist:
                recovery_email_message = Text(
                    _(
                        "Add a recovery email to retain access when single-sign on is not available. "
                        "Go to {link_start}your Account Settings{link_end}.")
                ).format(
                    link_start=HTML("<a href='{account_setting_page}'>").format(
                        account_setting_page=reverse('account_settings'),
                    ),
                    link_end=HTML("</a>")
                )
        else:
            recovery_email_activation_message = Text(
                _(
                    "Recovery email is not activated yet. "
                    "Kindly visit your email and follow the instructions to activate it."
                )
            )


    # Disable lookup of Enterprise consent_required_course due to ENT-727
    # Will re-enable after fixing WL-1315
    consent_required_courses = set()
    enterprise_customer_name = None

    # Account activation message
    account_activation_messages = [
        message for message in messages.get_messages(request) if 'account-activation' in message.tags
    ]

    # Global staff can see what courses encountered an error on their dashboard
    staff_access = False
    errored_courses = {}
    if has_access(user, 'staff', 'global'):
        # Show any courses that encountered an error on load
        staff_access = True
        errored_courses = modulestore().get_errored_courses()

    show_courseware_links_for = {
        enrollment.course_id: has_access(request.user, 'load', enrollment.course_overview)
        for enrollment in course_enrollments
    }

    # Find programs associated with course runs being displayed. This information
    # is passed in the template context to allow rendering of program-related
    # information on the dashboard.
    meter = ProgramProgressMeter(request.site, user, enrollments=course_enrollments)
    ecommerce_service = EcommerceService()
    inverted_programs = meter.invert_programs()

    urls, programs_data = {}, {}
    bundles_on_dashboard_flag = WaffleFlag(experiments_namespace, u'bundles_on_dashboard', __name__)

    # TODO: Delete this code and the relevant HTML code after testing LEARNER-3072 is complete
    if bundles_on_dashboard_flag.is_enabled() and inverted_programs and list(inverted_programs.items()):
        if len(course_enrollments) < 4:
            for program in inverted_programs.values():
                try:
                    program_uuid = program[0]['uuid']
                    program_data = get_programs(uuid=program_uuid)
                    program_data = ProgramDataExtender(program_data, request.user).extend()
                    skus = program_data.get('skus')
                    checkout_page_url = ecommerce_service.get_checkout_page_url(*skus)
                    program_data['completeProgramURL'] = checkout_page_url + '&bundle=' + program_data.get('uuid')
                    programs_data[program_uuid] = program_data
                except:  # pylint: disable=bare-except
                    pass

    # Construct a dictionary of course mode information
    # used to render the course list.  We re-use the course modes dict
    # we loaded earlier to avoid hitting the database.
    course_mode_info = {
        enrollment.course_id: complete_course_mode_info(
            enrollment.course_id, enrollment,
            modes=course_modes_by_course[enrollment.course_id]
        )
        for enrollment in course_enrollments
    }

    # Determine the per-course verification status
    # This is a dictionary in which the keys are course locators
    # and the values are one of:
    #
    # VERIFY_STATUS_NEED_TO_VERIFY
    # VERIFY_STATUS_SUBMITTED
    # VERIFY_STATUS_APPROVED
    # VERIFY_STATUS_MISSED_DEADLINE
    #
    # Each of which correspond to a particular message to display
    # next to the course on the dashboard.
    #
    # If a course is not included in this dictionary,
    # there is no verification messaging to display.
    verify_status_by_course = check_verify_status_by_course(user, course_enrollments)
    cert_statuses = {
        enrollment.course_id: cert_info(request.user, enrollment.course_overview)
        for enrollment in course_enrollments
    }

    # only show email settings for Mongo course and when bulk email is turned on
    show_email_settings_for = frozenset(
        enrollment.course_id for enrollment in course_enrollments if (
            is_bulk_email_feature_enabled(enrollment.course_id)
        )
    )

    # Verification Attempts
    # Used to generate the "you must reverify for course x" banner
    verification_status = IDVerificationService.user_status(user)
    verification_errors = get_verification_error_reasons_for_display(verification_status['error'])

    # Gets data for midcourse reverifications, if any are necessary or have failed
    statuses = ["approved", "denied", "pending", "must_reverify"]
    reverifications = reverification_info(statuses)

    enrolled_courses_either_paid = frozenset(
        enrollment.course_id for enrollment in course_enrollments
        if enrollment.is_paid_course()
    )

    # If there are *any* denied reverifications that have not been toggled off,
    # we'll display the banner
    denied_banner = any(item.display for item in reverifications["denied"])

    # get list of courses having pre-requisites yet to be completed
    courses_having_prerequisites = frozenset(
        enrollment.course_id for enrollment in course_enrollments
        if enrollment.course_overview.pre_requisite_courses
    )
    courses_requirements_not_met = get_pre_requisite_courses_not_completed(user, courses_having_prerequisites)

    site_domain = request.site
    if 'notlive' in request.GET:
        if 'viatris' in str(site_domain):
            redirect_message = _("The webinar you are looking for does not start until {date}.").format(
                date=request.GET['notlive']
            )
        else:
            redirect_message = _("The course you are looking for does not start until {date}.").format(
                date=request.GET['notlive']
            )

    elif 'course_closed' in request.GET:
        redirect_message = _("The course you are looking for is closed for enrollment as of {date}.").format(
            date=request.GET['course_closed']
        )
    elif 'access_response_error' in request.GET:
        # This can be populated in a generalized way with fields from access response errors
        redirect_message = request.GET['access_response_error']
    else:
        redirect_message = ''

    valid_verification_statuses = ['approved', 'must_reverify', 'pending', 'expired']
    display_sidebar_on_dashboard = verification_status['status'] in valid_verification_statuses and \
        verification_status['should_display']

    # Filter out any course enrollment course cards that are associated with fulfilled entitlements
    for entitlement in [e for e in course_entitlements if e.enrollment_course_run is not None]:
        course_enrollments = [
            enr for enr in course_enrollments if entitlement.enrollment_course_run.course_id != enr.course_id
        ]

    context = {
        'urls': urls,
        'programs_data': programs_data,
        'enterprise_message': enterprise_message,
        'consent_required_courses': consent_required_courses,
        'enterprise_customer_name': enterprise_customer_name,
        'enrollment_message': enrollment_message,
        'redirect_message': Text(redirect_message),
        'account_activation_messages': account_activation_messages,
        'activate_account_message': activate_account_message,
        'course_enrollments': course_enrollments,
        'course_entitlements': course_entitlements,
        'course_entitlement_available_sessions': course_entitlement_available_sessions,
        'unfulfilled_entitlement_pseudo_sessions': unfulfilled_entitlement_pseudo_sessions,
        'course_optouts': course_optouts,
        'staff_access': staff_access,
        'errored_courses': errored_courses,
        'show_courseware_links_for': show_courseware_links_for,
        'all_course_modes': course_mode_info,
        'cert_statuses': cert_statuses,
        'credit_statuses': _credit_statuses(user, course_enrollments),
        'show_email_settings_for': show_email_settings_for,
        'reverifications': reverifications,
        'verification_display': verification_status['should_display'],
        'verification_status': verification_status['status'],
        'verification_expiry': verification_status['verification_expiry'],
        'verification_status_by_course': verify_status_by_course,
        'verification_errors': verification_errors,
        'denied_banner': denied_banner,
        'billing_email': settings.PAYMENT_SUPPORT_EMAIL,
        'user': user,
        'logout_url': reverse('logout'),
        'platform_name': platform_name,
        'enrolled_courses_either_paid': enrolled_courses_either_paid,
        'provider_states': [],
        'courses_requirements_not_met': courses_requirements_not_met,
        'nav_hidden': True,
        'inverted_programs': inverted_programs,
        'show_program_listing': ProgramsApiConfig.is_enabled(),
        'show_dashboard_tabs': True,
        'disable_courseware_js': True,
        'display_course_modes_on_dashboard': enable_verified_certificates and display_course_modes_on_dashboard,
        'display_sidebar_on_dashboard': display_sidebar_on_dashboard,
        'display_sidebar_account_activation_message': not(user.is_active or hide_dashboard_courses_until_activated),
        'display_dashboard_courses': (user.is_active or not hide_dashboard_courses_until_activated),
        'empty_dashboard_message': empty_dashboard_message,
        'recovery_email_message': recovery_email_message,
        'recovery_email_activation_message': recovery_email_activation_message,
        'enterprise_learner_portal_enabled_message': enterprise_learner_portal_enabled_message,
        'show_load_all_courses_link': show_load_all_courses_link(user, course_limit, course_enrollments),
        # TODO START: clean up as part of REVEM-199 (START)
        'course_info': get_dashboard_course_info(user, course_enrollments),
        # TODO START: clean up as part of REVEM-199 (END)
        #added by dev 
        'courseslist':courseslist,
        'lectureslist':lectureslist,
    }

    context_from_plugins = get_plugins_view_context(
        ProjectType.LMS,
        COURSE_DASHBOARD_PLUGIN_VIEW_NAME,
        context
    )
    context.update(context_from_plugins)

    course = None
    context.update(
        get_experiment_user_metadata_context(
            course,
            user,
        )
    )
    if ecommerce_service.is_enabled(request.user):
        context.update({
            'use_ecommerce_payment_flow': True,
            'ecommerce_payment_page': ecommerce_service.payment_page_url(),
        })

    # Gather urls for course card resume buttons.
    resume_button_urls = ['' for entitlement in course_entitlements]
    for url in get_resume_urls_for_enrollments(user, course_enrollments).values():
        resume_button_urls.append(url)
    # There must be enough urls for dashboard.html. Template creates course
    # cards for "enrollments + entitlements".
    context.update({
        'resume_button_urls': resume_button_urls
    })

    return render_to_response('dashboard.html', context)
示例#7
0
    def get(self, request, course_id, error=None):
        """Displays the course mode choice page.

        Args:
            request (`Request`): The Django Request object.
            course_id (unicode): The slash-separated course key.

        Keyword Args:
            error (unicode): If provided, display this error message
                on the page.

        Returns:
            Response

        """
        course_key = CourseKey.from_string(course_id)

        # Check whether the user has access to this course
        # based on country access rules.
        embargo_redirect = embargo_api.redirect_if_blocked(
            course_key,
            user=request.user,
            ip_address=get_ip(request),
            url=request.path
        )
        if embargo_redirect:
            return redirect(embargo_redirect)

        enrollment_mode, is_active = CourseEnrollment.enrollment_mode_for_user(request.user, course_key)
        modes = CourseMode.modes_for_course_dict(course_key)
        ecommerce_service = EcommerceService()

        # We assume that, if 'professional' is one of the modes, it should be the *only* mode.
        # If there are both modes, default to non-id-professional.
        has_enrolled_professional = (CourseMode.is_professional_slug(enrollment_mode) and is_active)
        if CourseMode.has_professional_mode(modes) and not has_enrolled_professional:
            purchase_workflow = request.GET.get("purchase_workflow", "single")
            verify_url = reverse('verify_student_start_flow', kwargs={'course_id': unicode(course_key)})
            redirect_url = "{url}?purchase_workflow={workflow}".format(url=verify_url, workflow=purchase_workflow)
            if ecommerce_service.is_enabled(request.user):
                professional_mode = modes.get(CourseMode.NO_ID_PROFESSIONAL_MODE) or modes.get(CourseMode.PROFESSIONAL)
                if purchase_workflow == "single" and professional_mode.sku:
                    redirect_url = ecommerce_service.get_checkout_page_url(professional_mode.sku)
                if purchase_workflow == "bulk" and professional_mode.bulk_sku:
                    redirect_url = ecommerce_service.get_checkout_page_url(professional_mode.bulk_sku)
            return redirect(redirect_url)

        course = modulestore().get_course(course_key)

        # If there isn't a verified mode available, then there's nothing
        # to do on this page.  Send the user to the dashboard.
        if not CourseMode.has_verified_mode(modes):
            return redirect(reverse('dashboard'))

        # If a user has already paid, redirect them to the dashboard.
        if is_active and (enrollment_mode in CourseMode.VERIFIED_MODES + [CourseMode.NO_ID_PROFESSIONAL_MODE]):
            # If the course has started redirect to course home instead
            if course.has_started():
                return redirect(reverse('openedx.course_experience.course_home', kwargs={'course_id': course_key}))
            return redirect(reverse('dashboard'))

        donation_for_course = request.session.get("donation_for_course", {})
        chosen_price = donation_for_course.get(unicode(course_key), None)

        if CourseEnrollment.is_enrollment_closed(request.user, course):
            locale = to_locale(get_language())
            enrollment_end_date = format_datetime(course.enrollment_end, 'short', locale=locale)
            params = urllib.urlencode({'course_closed': enrollment_end_date})
            return redirect('{0}?{1}'.format(reverse('dashboard'), params))

        # When a credit mode is available, students will be given the option
        # to upgrade from a verified mode to a credit mode at the end of the course.
        # This allows students who have completed photo verification to be eligible
        # for univerity credit.
        # Since credit isn't one of the selectable options on the track selection page,
        # we need to check *all* available course modes in order to determine whether
        # a credit mode is available.  If so, then we show slightly different messaging
        # for the verified track.
        has_credit_upsell = any(
            CourseMode.is_credit_mode(mode) for mode
            in CourseMode.modes_for_course(course_key, only_selectable=False)
        )
        course_id = text_type(course_key)

        context = {
            "course_modes_choose_url": reverse(
                "course_modes_choose",
                kwargs={'course_id': course_id}
            ),
            "modes": modes,
            "has_credit_upsell": has_credit_upsell,
            "course_name": course.display_name_with_default,
            "course_org": course.display_org_with_default,
            "course_num": course.display_number_with_default,
            "chosen_price": chosen_price,
            "error": error,
            "responsive": True,
            "nav_hidden": True,
            "content_gating_enabled": ContentTypeGatingConfig.enabled_for_enrollment(
                user=request.user,
                course_key=course_key
            ),
            "course_duration_limit_enabled": CourseDurationLimitConfig.enabled_for_enrollment(
                user=request.user,
                course_key=course_key
            ),
        }
        context.update(
            get_experiment_user_metadata_context(
                course,
                request.user,
            )
        )

        title_content = _("Congratulations!  You are now enrolled in {course_name}").format(
            course_name=course.display_name_with_default
        )

        context["title_content"] = title_content

        if "verified" in modes:
            verified_mode = modes["verified"]
            context["suggested_prices"] = [
                decimal.Decimal(x.strip())
                for x in verified_mode.suggested_prices.split(",")
                if x.strip()
            ]
            context["currency"] = verified_mode.currency.upper()
            context["min_price"] = verified_mode.min_price
            context["verified_name"] = verified_mode.name
            context["verified_description"] = verified_mode.description

            if verified_mode.sku:
                context["use_ecommerce_payment_flow"] = ecommerce_service.is_enabled(request.user)
                context["ecommerce_payment_page"] = ecommerce_service.payment_page_url()
                context["sku"] = verified_mode.sku
                context["bulk_sku"] = verified_mode.bulk_sku

        context['currency_data'] = []
        if waffle.switch_is_active('local_currency'):
            if 'edx-price-l10n' not in request.COOKIES:
                currency_data = get_currency_data()
                try:
                    context['currency_data'] = json.dumps(currency_data)
                except TypeError:
                    pass
        return render_to_response("course_modes/choose.html", context)
示例#8
0
    def get(self, request, course_id, error=None):  # lint-amnesty, pylint: disable=too-many-statements
        """Displays the course mode choice page.

        Args:
            request (`Request`): The Django Request object.
            course_id (unicode): The slash-separated course key.

        Keyword Args:
            error (unicode): If provided, display this error message
                on the page.

        Returns:
            Response

        """
        course_key = CourseKey.from_string(course_id)

        # Check whether the user has access to this course
        # based on country access rules.
        embargo_redirect = embargo_api.redirect_if_blocked(
            course_key,
            user=request.user,
            ip_address=get_client_ip(request)[0],
            url=request.path)
        if embargo_redirect:
            return redirect(embargo_redirect)

        enrollment_mode, is_active = CourseEnrollment.enrollment_mode_for_user(
            request.user, course_key)

        increment('track-selection.{}.{}'.format(
            enrollment_mode, 'active' if is_active else 'inactive'))
        increment('track-selection.views')

        if enrollment_mode is None:
            LOG.info(
                'Rendering track selection for unenrolled user, referred by %s',
                request.META.get('HTTP_REFERER'))

        modes = CourseMode.modes_for_course_dict(course_key)
        ecommerce_service = EcommerceService()

        # We assume that, if 'professional' is one of the modes, it should be the *only* mode.
        # If there are both modes, default to 'no-id-professional'.
        has_enrolled_professional = (
            CourseMode.is_professional_slug(enrollment_mode) and is_active)
        if CourseMode.has_professional_mode(
                modes) and not has_enrolled_professional:
            purchase_workflow = request.GET.get("purchase_workflow", "single")
            redirect_url = IDVerificationService.get_verify_location(
                course_id=course_key)
            if ecommerce_service.is_enabled(request.user):
                professional_mode = modes.get(
                    CourseMode.NO_ID_PROFESSIONAL_MODE) or modes.get(
                        CourseMode.PROFESSIONAL)
                if purchase_workflow == "single" and professional_mode.sku:
                    redirect_url = ecommerce_service.get_checkout_page_url(
                        professional_mode.sku)
                if purchase_workflow == "bulk" and professional_mode.bulk_sku:
                    redirect_url = ecommerce_service.get_checkout_page_url(
                        professional_mode.bulk_sku)
            return redirect(redirect_url)

        course = modulestore().get_course(course_key)

        # If there isn't a verified mode available, then there's nothing
        # to do on this page.  Send the user to the dashboard.
        if not CourseMode.has_verified_mode(modes):
            return self._redirect_to_course_or_dashboard(
                course, course_key, request.user)

        # If a user has already paid, redirect them to the dashboard.
        if is_active and (enrollment_mode in CourseMode.VERIFIED_MODES +
                          [CourseMode.NO_ID_PROFESSIONAL_MODE]):
            return self._redirect_to_course_or_dashboard(
                course, course_key, request.user)

        donation_for_course = request.session.get("donation_for_course", {})
        chosen_price = donation_for_course.get(str(course_key), None)

        if CourseEnrollment.is_enrollment_closed(request.user, course):
            locale = to_locale(get_language())
            enrollment_end_date = format_datetime(course.enrollment_end,
                                                  'short',
                                                  locale=locale)
            params = six.moves.urllib.parse.urlencode(
                {'course_closed': enrollment_end_date})
            return redirect('{}?{}'.format(reverse('dashboard'), params))

        # When a credit mode is available, students will be given the option
        # to upgrade from a verified mode to a credit mode at the end of the course.
        # This allows students who have completed photo verification to be eligible
        # for university credit.
        # Since credit isn't one of the selectable options on the track selection page,
        # we need to check *all* available course modes in order to determine whether
        # a credit mode is available.  If so, then we show slightly different messaging
        # for the verified track.
        has_credit_upsell = any(
            CourseMode.is_credit_mode(mode)
            for mode in CourseMode.modes_for_course(course_key,
                                                    only_selectable=False))
        course_id = str(course_key)
        gated_content = ContentTypeGatingConfig.enabled_for_enrollment(
            user=request.user, course_key=course_key)
        context = {
            "course_modes_choose_url":
            reverse("course_modes_choose", kwargs={'course_id': course_id}),
            "modes":
            modes,
            "has_credit_upsell":
            has_credit_upsell,
            "course_name":
            course.display_name_with_default,
            "course_org":
            course.display_org_with_default,
            "course_num":
            course.display_number_with_default,
            "chosen_price":
            chosen_price,
            "error":
            error,
            "responsive":
            True,
            "nav_hidden":
            True,
            "content_gating_enabled":
            gated_content,
            "course_duration_limit_enabled":
            CourseDurationLimitConfig.enabled_for_enrollment(
                request.user, course),
        }
        context.update(
            get_experiment_user_metadata_context(
                course,
                request.user,
            ))

        title_content = ''
        if enrollment_mode:
            title_content = _(
                "Congratulations!  You are now enrolled in {course_name}"
            ).format(course_name=course.display_name_with_default)

        context["title_content"] = title_content

        if "verified" in modes:
            verified_mode = modes["verified"]
            context["suggested_prices"] = [
                decimal.Decimal(x.strip())
                for x in verified_mode.suggested_prices.split(",")
                if x.strip()
            ]
            price_before_discount = verified_mode.min_price
            course_price = price_before_discount
            enterprise_customer = enterprise_customer_for_request(request)
            LOG.info(
                '[e-commerce calculate API] Going to hit the API for user [%s] linked to [%s] enterprise',
                request.user.username,
                enterprise_customer.get('name') if isinstance(
                    enterprise_customer, dict) else None  # Test Purpose
            )
            if enterprise_customer and verified_mode.sku:
                course_price = get_course_final_price(request.user,
                                                      verified_mode.sku,
                                                      price_before_discount)

            context["currency"] = verified_mode.currency.upper()
            context["currency_symbol"] = get_currency_symbol(
                verified_mode.currency.upper())
            context["min_price"] = course_price
            context["verified_name"] = verified_mode.name
            context["verified_description"] = verified_mode.description
            # if course_price is equal to price_before_discount then user doesn't entitle to any discount.
            if course_price != price_before_discount:
                context["price_before_discount"] = price_before_discount

            if verified_mode.sku:
                context[
                    "use_ecommerce_payment_flow"] = ecommerce_service.is_enabled(
                        request.user)
                context[
                    "ecommerce_payment_page"] = ecommerce_service.payment_page_url(
                    )
                context["sku"] = verified_mode.sku
                context["bulk_sku"] = verified_mode.bulk_sku

        context['currency_data'] = []
        if waffle.switch_is_active('local_currency'):
            if 'edx-price-l10n' not in request.COOKIES:
                currency_data = get_currency_data()
                try:
                    context['currency_data'] = json.dumps(currency_data)
                except TypeError:
                    pass

        language = get_language()
        context['track_links'] = get_verified_track_links(language)

        duration = get_user_course_duration(request.user, course)
        deadline = duration and get_user_course_expiration_date(
            request.user, course)
        if deadline:
            formatted_audit_access_date = strftime_localized_html(
                deadline, 'SHORT_DATE')
            context['audit_access_deadline'] = formatted_audit_access_date
        fbe_is_on = deadline and gated_content

        # Route to correct Track Selection page.
        # REV-2133 TODO Value Prop: remove waffle flag after testing is completed
        # and happy path version is ready to be rolled out to all users.
        if VALUE_PROP_TRACK_SELECTION_FLAG.is_enabled():
            if not error:  # TODO: Remove by executing REV-2355
                if not enterprise_customer_for_request(
                        request):  # TODO: Remove by executing REV-2342
                    if fbe_is_on:
                        return render_to_response("course_modes/fbe.html",
                                                  context)
                    else:
                        return render_to_response("course_modes/unfbe.html",
                                                  context)

        # If error or enterprise_customer, failover to old choose.html page
        return render_to_response("course_modes/choose.html", context)
示例#9
0
    def get(self, request, course_id, error=None):
        """Displays the course mode choice page.

        Args:
            request (`Request`): The Django Request object.
            course_id (unicode): The slash-separated course key.

        Keyword Args:
            error (unicode): If provided, display this error message
                on the page.

        Returns:
            Response

        """
        course_key = CourseKey.from_string(course_id)

        # Check whether the user has access to this course
        # based on country access rules.
        embargo_redirect = embargo_api.redirect_if_blocked(
            course_key,
            user=request.user,
            ip_address=get_ip(request),
            url=request.path
        )
        if embargo_redirect:
            return redirect(embargo_redirect)

        enrollment_mode, is_active = CourseEnrollment.enrollment_mode_for_user(request.user, course_key)
        modes = CourseMode.modes_for_course_dict(course_key)
        ecommerce_service = EcommerceService()

        # We assume that, if 'professional' is one of the modes, it should be the *only* mode.
        # If there are both modes, default to non-id-professional.
        has_enrolled_professional = (CourseMode.is_professional_slug(enrollment_mode) and is_active)
        if CourseMode.has_professional_mode(modes) and not has_enrolled_professional:
            purchase_workflow = request.GET.get("purchase_workflow", "single")
            verify_url = reverse('verify_student_start_flow', kwargs={'course_id': unicode(course_key)})
            redirect_url = "{url}?purchase_workflow={workflow}".format(url=verify_url, workflow=purchase_workflow)
            if ecommerce_service.is_enabled(request.user):
                professional_mode = modes.get(CourseMode.NO_ID_PROFESSIONAL_MODE) or modes.get(CourseMode.PROFESSIONAL)
                if purchase_workflow == "single" and professional_mode.sku:
                    redirect_url = ecommerce_service.get_checkout_page_url(professional_mode.sku)
                if purchase_workflow == "bulk" and professional_mode.bulk_sku:
                    redirect_url = ecommerce_service.get_checkout_page_url(professional_mode.bulk_sku)
            return redirect(redirect_url)

        # If there isn't a verified mode available, then there's nothing
        # to do on this page.  Send the user to the dashboard.
        if not CourseMode.has_verified_mode(modes):
            return redirect(reverse('dashboard'))

        # If a user has already paid, redirect them to the dashboard.
        if is_active and (enrollment_mode in CourseMode.VERIFIED_MODES + [CourseMode.NO_ID_PROFESSIONAL_MODE]):
            return redirect(reverse('dashboard'))

        donation_for_course = request.session.get("donation_for_course", {})
        chosen_price = donation_for_course.get(unicode(course_key), None)

        course = modulestore().get_course(course_key)
        if CourseEnrollment.is_enrollment_closed(request.user, course):
            locale = to_locale(get_language())
            enrollment_end_date = format_datetime(course.enrollment_end, 'short', locale=locale)
            params = urllib.urlencode({'course_closed': enrollment_end_date})
            return redirect('{0}?{1}'.format(reverse('dashboard'), params))

        # When a credit mode is available, students will be given the option
        # to upgrade from a verified mode to a credit mode at the end of the course.
        # This allows students who have completed photo verification to be eligible
        # for univerity credit.
        # Since credit isn't one of the selectable options on the track selection page,
        # we need to check *all* available course modes in order to determine whether
        # a credit mode is available.  If so, then we show slightly different messaging
        # for the verified track.
        has_credit_upsell = any(
            CourseMode.is_credit_mode(mode) for mode
            in CourseMode.modes_for_course(course_key, only_selectable=False)
        )
        course_id = course_key.to_deprecated_string()
        context = {
            "course_modes_choose_url": reverse(
                "course_modes_choose",
                kwargs={'course_id': course_id}
            ),
            "modes": modes,
            "has_credit_upsell": has_credit_upsell,
            "course_name": course.display_name_with_default_escaped,
            "course_org": course.display_org_with_default,
            "course_num": course.display_number_with_default,
            "chosen_price": chosen_price,
            "error": error,
            "responsive": True,
            "nav_hidden": True,
        }
        context.update(
            get_experiment_user_metadata_context(
                request,
                course,
                request.user,
            )
        )

        title_content = _("Congratulations!  You are now enrolled in {course_name}").format(
            course_name=course.display_name_with_default_escaped
        )
        enterprise_learner_data = enterprise_api.get_enterprise_learner_data(site=request.site, user=request.user)
        if enterprise_learner_data:
            enterprise_learner = enterprise_learner_data[0]
            is_course_in_enterprise_catalog = enterprise_api.is_course_in_enterprise_catalog(
                site=request.site,
                course_id=course_id,
                enterprise_catalog_id=enterprise_learner['enterprise_customer']['catalog']
            )

            if is_course_in_enterprise_catalog:
                partner_names = partner_name = course.display_organization \
                    if course.display_organization else course.org
                enterprise_name = enterprise_learner['enterprise_customer']['name']
                organizations = organization_api.get_course_organizations(course_id=course.id)
                if organizations:
                    partner_names = ' and '.join([org.get('name', partner_name) for org in organizations])

                title_content = _("Welcome, {username}! You are about to enroll in {course_name},"
                                  " from {partner_names}, sponsored by {enterprise_name}. Please select your enrollment"
                                  " information below.").format(
                    username=request.user.username,
                    course_name=course.display_name_with_default_escaped,
                    partner_names=partner_names,
                    enterprise_name=enterprise_name
                )

                # Hide the audit modes for this enterprise customer, if necessary
                if not enterprise_learner['enterprise_customer'].get('enable_audit_enrollment'):
                    for audit_mode in CourseMode.AUDIT_MODES:
                        modes.pop(audit_mode, None)

        context["title_content"] = title_content

        if "verified" in modes:
            verified_mode = modes["verified"]
            context["suggested_prices"] = [
                decimal.Decimal(x.strip())
                for x in verified_mode.suggested_prices.split(",")
                if x.strip()
            ]
            context["currency"] = verified_mode.currency.upper()
            context["min_price"] = verified_mode.min_price
            context["verified_name"] = verified_mode.name
            context["verified_description"] = verified_mode.description

            if verified_mode.sku:
                context["use_ecommerce_payment_flow"] = ecommerce_service.is_enabled(request.user)
                context["ecommerce_payment_page"] = ecommerce_service.payment_page_url()
                context["sku"] = verified_mode.sku
                context["bulk_sku"] = verified_mode.bulk_sku

        return render_to_response("course_modes/choose.html", context)
示例#10
0
    def _create_courseware_context(self, request):
        """
        Returns and creates the rendering context for the courseware.
        Also returns the table of contents for the courseware.
        """
        course_url_name = default_course_url_name(self.course.id)
        course_url = reverse(course_url_name,
                             kwargs={'course_id': unicode(self.course.id)})

        courseware_context = {
            'csrf':
            csrf(self.request)['csrf_token'],
            'course':
            self.course,
            'course_url':
            course_url,
            'chapter':
            self.chapter,
            'section':
            self.section,
            'init':
            '',
            'fragment':
            Fragment(),
            'staff_access':
            self.is_staff,
            'masquerade':
            self.masquerade,
            'supports_preview_menu':
            True,
            'studio_url':
            get_studio_url(self.course, 'course'),
            'xqa_server':
            settings.FEATURES.get('XQA_SERVER', "http://your_xqa_server.com"),
            'bookmarks_api_url':
            reverse('bookmarks'),
            'language_preference':
            self._get_language_preference(),
            'disable_optimizely':
            not WaffleSwitchNamespace('RET').is_enabled(
                'enable_optimizely_in_courseware'),
            'section_title':
            None,
            'sequence_title':
            None,
            'disable_accordion':
            COURSE_OUTLINE_PAGE_FLAG.is_enabled(self.course.id),
        }
        courseware_context.update(
            get_experiment_user_metadata_context(
                self.course,
                self.effective_user,
            ))
        table_of_contents = toc_for_course(
            self.effective_user,
            self.request,
            self.course,
            self.chapter_url_name,
            self.section_url_name,
            self.field_data_cache,
        )
        courseware_context['accordion'] = render_accordion(
            self.request,
            self.course,
            table_of_contents['chapters'],
        )

        courseware_context['course_sock_fragment'] = CourseSockFragmentView(
        ).render_to_fragment(request, course=self.course)

        # entrance exam data
        self._add_entrance_exam_to_context(courseware_context)

        # staff masquerading data
        if not check_course_open_for_learner(self.effective_user, self.course):
            # Disable student view button if user is staff and
            # course is not yet visible to students.
            courseware_context['disable_student_access'] = True
            courseware_context['supports_preview_menu'] = False

        if self.section:
            # chromeless data
            if self.section.chrome:
                chrome = [
                    s.strip() for s in self.section.chrome.lower().split(",")
                ]
                if 'accordion' not in chrome:
                    courseware_context['disable_accordion'] = True
                if 'tabs' not in chrome:
                    courseware_context['disable_tabs'] = True

            # default tab
            if self.section.default_tab:
                courseware_context['default_tab'] = self.section.default_tab

            # section data
            courseware_context[
                'section_title'] = self.section.display_name_with_default
            section_context = self._create_section_context(
                table_of_contents['previous_of_active_section'],
                table_of_contents['next_of_active_section'],
            )
            courseware_context['fragment'] = self.section.render(
                STUDENT_VIEW, section_context)
            if self.section.position and self.section.has_children:
                display_items = self.section.get_display_items()
                if display_items:
                    try:
                        courseware_context['sequence_title'] = display_items[self.section.position - 1] \
                            .display_name_with_default
                    except IndexError:
                        log.exception(
                            "IndexError loading courseware for user %s, course %s, section %s, position %d. Total items: %d. URL: %s",
                            self.real_user.username,
                            self.course.id,
                            self.section.display_name_with_default,
                            self.section.position,
                            len(display_items),
                            self.url,
                        )
                        raise
        return courseware_context
示例#11
0
    def _create_courseware_context(self, request):
        """
        Returns and creates the rendering context for the courseware.
        Also returns the table of contents for the courseware.
        """
        course_url_name = default_course_url_name(self.course.id)
        course_url = reverse(course_url_name, kwargs={'course_id': unicode(self.course.id)})

        courseware_context = {
            'csrf': csrf(self.request)['csrf_token'],
            'course': self.course,
            'course_url': course_url,
            'chapter': self.chapter,
            'section': self.section,
            'init': '',
            'fragment': Fragment(),
            'staff_access': self.is_staff,
            'masquerade': self.masquerade,
            'supports_preview_menu': True,
            'studio_url': get_studio_url(self.course, 'course'),
            'xqa_server': settings.FEATURES.get('XQA_SERVER', "http://your_xqa_server.com"),
            'bookmarks_api_url': reverse('bookmarks'),
            'language_preference': self._get_language_preference(),
            'disable_optimizely': not WaffleSwitchNamespace('RET').is_enabled('enable_optimizely_in_courseware'),
            'section_title': None,
            'sequence_title': None,
            'disable_accordion': COURSE_OUTLINE_PAGE_FLAG.is_enabled(self.course.id),
        }
        courseware_context.update(
            get_experiment_user_metadata_context(
                self.course,
                self.effective_user,
            )
        )
        table_of_contents = toc_for_course(
            self.effective_user,
            self.request,
            self.course,
            self.chapter_url_name,
            self.section_url_name,
            self.field_data_cache,
        )
        courseware_context['accordion'] = render_accordion(
            self.request,
            self.course,
            table_of_contents['chapters'],
        )

        courseware_context['course_sock_fragment'] = CourseSockFragmentView().render_to_fragment(
            request, course=self.course)

        # entrance exam data
        self._add_entrance_exam_to_context(courseware_context)

        if self.section:
            # chromeless data
            if self.section.chrome:
                chrome = [s.strip() for s in self.section.chrome.lower().split(",")]
                if 'accordion' not in chrome:
                    courseware_context['disable_accordion'] = True
                if 'tabs' not in chrome:
                    courseware_context['disable_tabs'] = True

            # default tab
            if self.section.default_tab:
                courseware_context['default_tab'] = self.section.default_tab

            # section data
            courseware_context['section_title'] = self.section.display_name_with_default
            section_context = self._create_section_context(
                table_of_contents['previous_of_active_section'],
                table_of_contents['next_of_active_section'],
            )

            courseware_context['fragment'] = self.section.render(self.view, section_context)

            if self.section.position and self.section.has_children:
                self._add_sequence_title_to_context(courseware_context)

        return courseware_context
示例#12
0
    def _create_courseware_context(self, request):
        """
        Returns and creates the rendering context for the courseware.
        Also returns the table of contents for the courseware.
        """
        from lms.urls import RESET_COURSE_DEADLINES_NAME

        course_url_name = default_course_url_name(self.course.id)
        course_url = reverse(
            course_url_name,
            kwargs={'course_id': six.text_type(self.course.id)})
        show_search = (
            settings.FEATURES.get('ENABLE_COURSEWARE_SEARCH') or
            (settings.FEATURES.get('ENABLE_COURSEWARE_SEARCH_FOR_COURSE_STAFF')
             and self.is_staff))
        staff_access = self.is_staff

        allow_anonymous = check_public_access(self.course,
                                              [COURSE_VISIBILITY_PUBLIC])
        display_reset_dates_banner = False
        if not allow_anonymous and RELATIVE_DATES_FLAG.is_enabled(
                self.course.id):
            display_reset_dates_banner = reset_deadlines_banner_should_display(
                self.course_key, request)

        reset_deadlines_url = reverse(RESET_COURSE_DEADLINES_NAME
                                      ) if display_reset_dates_banner else None

        reset_deadlines_redirect_url_base = COURSE_HOME_VIEW_NAME if reset_deadlines_url else None

        courseware_context = {
            'csrf':
            csrf(self.request)['csrf_token'],
            'course':
            self.course,
            'course_url':
            course_url,
            'chapter':
            self.chapter,
            'section':
            self.section,
            'init':
            '',
            'fragment':
            Fragment(),
            'staff_access':
            staff_access,
            'can_masquerade':
            self.can_masquerade,
            'masquerade':
            self.masquerade,
            'supports_preview_menu':
            True,
            'studio_url':
            get_studio_url(self.course, 'course'),
            'xqa_server':
            settings.FEATURES.get('XQA_SERVER', "http://your_xqa_server.com"),
            'bookmarks_api_url':
            reverse('bookmarks'),
            'language_preference':
            self._get_language_preference(),
            'disable_optimizely':
            not WaffleSwitchNamespace('RET').is_enabled(
                'enable_optimizely_in_courseware'),
            'section_title':
            None,
            'sequence_title':
            None,
            'disable_accordion':
            COURSE_OUTLINE_PAGE_FLAG.is_enabled(self.course.id),
            'show_search':
            show_search,
            'relative_dates_is_enabled':
            RELATIVE_DATES_FLAG.is_enabled(self.course.id),
            'display_reset_dates_banner':
            display_reset_dates_banner,
            'reset_deadlines_url':
            reset_deadlines_url,
            'reset_deadlines_redirect_url_base':
            reset_deadlines_redirect_url_base,
            'reset_deadlines_redirect_url_id_dict': {
                'course_id': str(self.course.id)
            },
        }
        courseware_context.update(
            get_experiment_user_metadata_context(
                self.course,
                self.effective_user,
            ))
        table_of_contents = toc_for_course(
            self.effective_user,
            self.request,
            self.course,
            self.chapter_url_name,
            self.section_url_name,
            self.field_data_cache,
        )
        courseware_context['accordion'] = render_accordion(
            self.request,
            self.course,
            table_of_contents['chapters'],
        )

        courseware_context['course_sock_fragment'] = CourseSockFragmentView(
        ).render_to_fragment(request, course=self.course)

        # entrance exam data
        self._add_entrance_exam_to_context(courseware_context)

        if self.section:
            # chromeless data
            if self.section.chrome:
                chrome = [
                    s.strip() for s in self.section.chrome.lower().split(",")
                ]
                if 'accordion' not in chrome:
                    courseware_context['disable_accordion'] = True
                if 'tabs' not in chrome:
                    courseware_context['disable_tabs'] = True

            # default tab
            if self.section.default_tab:
                courseware_context['default_tab'] = self.section.default_tab

            # section data
            courseware_context[
                'section_title'] = self.section.display_name_with_default
            section_context = self._create_section_context(
                table_of_contents['previous_of_active_section'],
                table_of_contents['next_of_active_section'],
            )
            courseware_context['fragment'] = self.section.render(
                self.view, section_context)

            if self.section.position and self.section.has_children:
                self._add_sequence_title_to_context(courseware_context)

        # Courseware MFE link
        if show_courseware_mfe_link(request.user, staff_access,
                                    self.course.id):
            courseware_context['microfrontend_link'] = self.microfrontend_url
        else:
            courseware_context['microfrontend_link'] = None

        return courseware_context
示例#13
0
    def _create_courseware_context(self, request):
        """
        Returns and creates the rendering context for the courseware.
        Also returns the table of contents for the courseware.
        """
        course_url_name = default_course_url_name(self.course.id)
        course_url = reverse(
            course_url_name,
            kwargs={'course_id': six.text_type(self.course.id)})
        show_search = (
            settings.FEATURES.get('ENABLE_COURSEWARE_SEARCH') or
            (settings.FEATURES.get('ENABLE_COURSEWARE_SEARCH_FOR_COURSE_STAFF')
             and self.is_staff))
        staff_access = self.is_staff

        reset_deadlines_url = reverse(
            'openedx.course_experience.reset_course_deadlines',
            kwargs={'course_id': six.text_type(self.course.id)})

        allow_anonymous = allow_public_access(self.course,
                                              [COURSE_VISIBILITY_PUBLIC])
        display_reset_dates_banner = False
        if not allow_anonymous and RELATIVE_DATES_FLAG.is_enabled(
                self.course.id):  # pylint: disable=too-many-nested-blocks
            course_overview = CourseOverview.objects.get(
                id=str(self.course_key))
            end_date = getattr(course_overview, 'end_date')
            if course_overview.self_paced and (not end_date
                                               or timezone.now() < end_date):
                if (CourseEnrollment.objects.filter(
                        course=course_overview,
                        user=request.user,
                        mode=CourseMode.VERIFIED).exists()):
                    course_block_tree = get_course_outline_block_tree(
                        request, str(self.course_key), request.user)
                    course_sections = course_block_tree.get('children', [])
                    for section in course_sections:
                        if display_reset_dates_banner:
                            break
                        for subsection in section.get('children', []):
                            if (not subsection.get('complete', True)
                                    and subsection.get(
                                        'due',
                                        timezone.now() + timedelta(1)) <
                                    timezone.now()):
                                display_reset_dates_banner = True
                                break

        courseware_context = {
            'csrf':
            csrf(self.request)['csrf_token'],
            'course':
            self.course,
            'course_url':
            course_url,
            'chapter':
            self.chapter,
            'section':
            self.section,
            'init':
            '',
            'fragment':
            Fragment(),
            'staff_access':
            staff_access,
            'can_masquerade':
            self.can_masquerade,
            'masquerade':
            self.masquerade,
            'supports_preview_menu':
            True,
            'studio_url':
            get_studio_url(self.course, 'course'),
            'xqa_server':
            settings.FEATURES.get('XQA_SERVER', "http://your_xqa_server.com"),
            'bookmarks_api_url':
            reverse('bookmarks'),
            'language_preference':
            self._get_language_preference(),
            'disable_optimizely':
            not WaffleSwitchNamespace('RET').is_enabled(
                'enable_optimizely_in_courseware'),
            'section_title':
            None,
            'sequence_title':
            None,
            'disable_accordion':
            COURSE_OUTLINE_PAGE_FLAG.is_enabled(self.course.id),
            'show_search':
            show_search,
            'relative_dates_is_enabled':
            RELATIVE_DATES_FLAG.is_enabled(self.course.id),
            'reset_deadlines_url':
            reset_deadlines_url,
            'display_reset_dates_banner':
            display_reset_dates_banner,
        }
        courseware_context.update(
            get_experiment_user_metadata_context(
                self.course,
                self.effective_user,
            ))
        table_of_contents = toc_for_course(
            self.effective_user,
            self.request,
            self.course,
            self.chapter_url_name,
            self.section_url_name,
            self.field_data_cache,
        )
        courseware_context['accordion'] = render_accordion(
            self.request,
            self.course,
            table_of_contents['chapters'],
        )

        courseware_context['course_sock_fragment'] = CourseSockFragmentView(
        ).render_to_fragment(request, course=self.course_overview)

        # entrance exam data
        self._add_entrance_exam_to_context(courseware_context)

        if self.section:
            # chromeless data
            if self.section.chrome:
                chrome = [
                    s.strip() for s in self.section.chrome.lower().split(",")
                ]
                if 'accordion' not in chrome:
                    courseware_context['disable_accordion'] = True
                if 'tabs' not in chrome:
                    courseware_context['disable_tabs'] = True

            # default tab
            if self.section.default_tab:
                courseware_context['default_tab'] = self.section.default_tab

            # section data
            courseware_context[
                'section_title'] = self.section.display_name_with_default
            section_context = self._create_section_context(
                table_of_contents['previous_of_active_section'],
                table_of_contents['next_of_active_section'],
            )
            courseware_context['fragment'] = self.section.render(
                self.view, section_context)

            if self.section.position and self.section.has_children:
                self._add_sequence_title_to_context(courseware_context)

        # Courseware MFE link
        if show_courseware_mfe_link(request.user, staff_access,
                                    self.course.id):
            if self.section:
                try:
                    unit_key = UsageKey.from_string(
                        request.GET.get('activate_block_id', ''))
                    # `activate_block_id` is typically a Unit (a.k.a. Vertical),
                    # but it can technically be any block type. Do a check to
                    # make sure it's really a Unit before we use it for the MFE.
                    if unit_key.block_type != 'vertical':
                        unit_key = None
                except InvalidKeyError:
                    unit_key = None

                courseware_context[
                    'microfrontend_link'] = get_microfrontend_url(
                        self.course.id, self.section.location, unit_key)
            else:
                courseware_context[
                    'microfrontend_link'] = get_microfrontend_url(
                        self.course.id)
        else:
            courseware_context['microfrontend_link'] = None

        return courseware_context
示例#14
0
    def _create_courseware_context(self, request):
        """
        Returns and creates the rendering context for the courseware.
        Also returns the table of contents for the courseware.
        """
        course_url_name = default_course_url_name(self.course.id)
        course_url = reverse(course_url_name, kwargs={'course_id': unicode(self.course.id)})

        courseware_context = {
            'csrf': csrf(self.request)['csrf_token'],
            'course': self.course,
            'course_url': course_url,
            'chapter': self.chapter,
            'section': self.section,
            'init': '',
            'fragment': Fragment(),
            'staff_access': self.is_staff,
            'masquerade': self.masquerade,
            'supports_preview_menu': True,
            'studio_url': get_studio_url(self.course, 'course'),
            'xqa_server': settings.FEATURES.get('XQA_SERVER', "http://your_xqa_server.com"),
            'bookmarks_api_url': reverse('bookmarks'),
            'language_preference': self._get_language_preference(),
            'disable_optimizely': not WaffleSwitchNamespace('RET').is_enabled('enable_optimizely_in_courseware'),
            'section_title': None,
            'sequence_title': None,
            'disable_accordion': COURSE_OUTLINE_PAGE_FLAG.is_enabled(self.course.id),
        }
        courseware_context.update(
            get_experiment_user_metadata_context(
                self.course,
                self.effective_user,
            )
        )
        table_of_contents = toc_for_course(
            self.effective_user,
            self.request,
            self.course,
            self.chapter_url_name,
            self.section_url_name,
            self.field_data_cache,
        )
        courseware_context['accordion'] = render_accordion(
            self.request,
            self.course,
            table_of_contents['chapters'],
        )

        courseware_context['course_sock_fragment'] = CourseSockFragmentView().render_to_fragment(
            request, course=self.course)

        # entrance exam data
        self._add_entrance_exam_to_context(courseware_context)

        # staff masquerading data
        if not check_course_open_for_learner(self.effective_user, self.course):
            # Disable student view button if user is staff and
            # course is not yet visible to students.
            courseware_context['disable_student_access'] = True
            courseware_context['supports_preview_menu'] = False

        if self.section:
            # chromeless data
            if self.section.chrome:
                chrome = [s.strip() for s in self.section.chrome.lower().split(",")]
                if 'accordion' not in chrome:
                    courseware_context['disable_accordion'] = True
                if 'tabs' not in chrome:
                    courseware_context['disable_tabs'] = True

            # default tab
            if self.section.default_tab:
                courseware_context['default_tab'] = self.section.default_tab

            # section data
            courseware_context['section_title'] = self.section.display_name_with_default
            section_context = self._create_section_context(
                table_of_contents['previous_of_active_section'],
                table_of_contents['next_of_active_section'],
            )
            courseware_context['fragment'] = self.section.render(STUDENT_VIEW, section_context)
            if self.section.position and self.section.has_children:
                display_items = self.section.get_display_items()
                if display_items:
                    try:
                        courseware_context['sequence_title'] = display_items[self.section.position - 1] \
                            .display_name_with_default
                    except IndexError:
                        log.exception(
                            "IndexError loading courseware for user %s, course %s, section %s, position %d. Total items: %d. URL: %s",
                            self.real_user.username,
                            self.course.id,
                            self.section.display_name_with_default,
                            self.section.position,
                            len(display_items),
                            self.url,
                        )
                        raise
        return courseware_context
示例#15
0
    def _create_courseware_context(self, request):
        """
        Returns and creates the rendering context for the courseware.
        Also returns the table of contents for the courseware.
        """

        course_url = default_course_url(self.course.id)
        show_search = (
            settings.FEATURES.get('ENABLE_COURSEWARE_SEARCH') or
            (settings.FEATURES.get('ENABLE_COURSEWARE_SEARCH_FOR_COURSE_STAFF') and self.is_staff)
        )
        staff_access = self.is_staff

        courseware_context = {
            'csrf': csrf(self.request)['csrf_token'],
            'course': self.course,
            'course_url': course_url,
            'chapter': self.chapter,
            'section': self.section,
            'init': '',
            'fragment': Fragment(),
            'staff_access': staff_access,
            'can_masquerade': self.can_masquerade,
            'masquerade': self.masquerade,
            'supports_preview_menu': True,
            'studio_url': get_studio_url(self.course, 'course'),
            'xqa_server': settings.FEATURES.get('XQA_SERVER', "http://your_xqa_server.com"),
            'bookmarks_api_url': reverse('bookmarks'),
            'language_preference': self._get_language_preference(),
            'disable_optimizely': not LegacyWaffleSwitchNamespace('RET').is_enabled('enable_optimizely_in_courseware'),
            'section_title': None,
            'sequence_title': None,
            'disable_accordion': not DISABLE_COURSE_OUTLINE_PAGE_FLAG.is_enabled(self.course.id),
            'show_search': show_search,
            'render_course_wide_assets': True,
        }
        courseware_context.update(
            get_experiment_user_metadata_context(
                self.course,
                self.effective_user,
            )
        )
        table_of_contents = toc_for_course(
            self.effective_user,
            self.request,
            self.course,
            self.chapter_url_name,
            self.section_url_name,
            self.field_data_cache,
        )
        courseware_context['accordion'] = render_accordion(
            self.request,
            self.course,
            table_of_contents['chapters'],
        )

        courseware_context['course_sock_fragment'] = CourseSockFragmentView().render_to_fragment(
            request, course=self.course)

        # entrance exam data
        self._add_entrance_exam_to_context(courseware_context)

        if self.section:
            # chromeless data
            if self.section.chrome:
                chrome = [s.strip() for s in self.section.chrome.lower().split(",")]
                if 'accordion' not in chrome:
                    courseware_context['disable_accordion'] = True
                if 'tabs' not in chrome:
                    courseware_context['disable_tabs'] = True

            # default tab
            if self.section.default_tab:
                courseware_context['default_tab'] = self.section.default_tab

            # section data
            courseware_context['section_title'] = self.section.display_name_with_default
            section_context = self._create_section_context(
                table_of_contents['previous_of_active_section'],
                table_of_contents['next_of_active_section'],
            )
            courseware_context['fragment'] = self.section.render(self.view, section_context)

            if self.section.position and self.section.has_children:
                self._add_sequence_title_to_context(courseware_context)

        # Courseware MFE link
        if courseware_mfe_is_advertised(
                is_global_staff=request.user.is_staff,
                is_course_staff=staff_access,
                course_key=self.course.id,
        ):
            courseware_context['microfrontend_link'] = self.microfrontend_url
        else:
            courseware_context['microfrontend_link'] = None

        return courseware_context
示例#16
0
    def _create_courseware_context(self, request):
        """
        Returns and creates the rendering context for the courseware.
        Also returns the table of contents for the courseware.
        """
        course_url_name = default_course_url_name(self.course.id)
        course_url = reverse(
            course_url_name,
            kwargs={'course_id': six.text_type(self.course.id)})
        show_search = (
            settings.FEATURES.get('ENABLE_COURSEWARE_SEARCH') or
            (settings.FEATURES.get('ENABLE_COURSEWARE_SEARCH_FOR_COURSE_STAFF')
             and self.is_staff))
        staff_access = self.is_staff

        courseware_context = {
            'csrf':
            csrf(self.request)['csrf_token'],
            'course':
            self.course,
            'course_url':
            course_url,
            'chapter':
            self.chapter,
            'section':
            self.section,
            'init':
            '',
            'fragment':
            Fragment(),
            'staff_access':
            staff_access,
            'can_masquerade':
            self.can_masquerade,
            'masquerade':
            self.masquerade,
            'supports_preview_menu':
            True,
            'studio_url':
            get_studio_url(self.course, 'course'),
            'xqa_server':
            settings.FEATURES.get('XQA_SERVER', "http://your_xqa_server.com"),
            'bookmarks_api_url':
            reverse('bookmarks'),
            'language_preference':
            self._get_language_preference(),
            'disable_optimizely':
            not WaffleSwitchNamespace('RET').is_enabled(
                'enable_optimizely_in_courseware'),
            'section_title':
            None,
            'sequence_title':
            None,
            'disable_accordion':
            COURSE_OUTLINE_PAGE_FLAG.is_enabled(self.course.id),
            'show_search':
            show_search,
        }
        courseware_context.update(
            get_experiment_user_metadata_context(
                self.course,
                self.effective_user,
            ))
        table_of_contents = toc_for_course(
            self.effective_user,
            self.request,
            self.course,
            self.chapter_url_name,
            self.section_url_name,
            self.field_data_cache,
        )
        courseware_context['accordion'] = render_accordion(
            self.request,
            self.course,
            table_of_contents['chapters'],
        )

        courseware_context['course_sock_fragment'] = CourseSockFragmentView(
        ).render_to_fragment(request, course=self.course_overview)

        # entrance exam data
        self._add_entrance_exam_to_context(courseware_context)

        if self.section:
            # chromeless data
            if self.section.chrome:
                chrome = [
                    s.strip() for s in self.section.chrome.lower().split(",")
                ]
                if 'accordion' not in chrome:
                    courseware_context['disable_accordion'] = True
                if 'tabs' not in chrome:
                    courseware_context['disable_tabs'] = True

            # default tab
            if self.section.default_tab:
                courseware_context['default_tab'] = self.section.default_tab

            # section data
            courseware_context[
                'section_title'] = self.section.display_name_with_default
            section_context = self._create_section_context(
                table_of_contents['previous_of_active_section'],
                table_of_contents['next_of_active_section'],
            )
            courseware_context['fragment'] = self.section.render(
                self.view, section_context)

            if self.section.position and self.section.has_children:
                self._add_sequence_title_to_context(courseware_context)

        # Courseware MFE link
        if show_courseware_mfe_link(request.user, staff_access,
                                    self.course.id):
            if self.section:
                try:
                    unit_key = UsageKey.from_string(
                        request.GET.get('activate_block_id', ''))
                    # `activate_block_id` is typically a Unit (a.k.a. Vertical),
                    # but it can technically be any block type. Do a check to
                    # make sure it's really a Unit before we use it for the MFE.
                    if unit_key.block_type != 'vertical':
                        unit_key = None
                except InvalidKeyError:
                    unit_key = None

                courseware_context[
                    'microfrontend_link'] = get_microfrontend_url(
                        self.course.id, self.section.location, unit_key)
            else:
                courseware_context[
                    'microfrontend_link'] = get_microfrontend_url(
                        self.course.id)
        else:
            courseware_context['microfrontend_link'] = None

        return courseware_context