Ejemplo n.º 1
0
    def render_to_fragment(self, request, course_id=None, **kwargs):
        """
        Render the course dates fragment.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)
        course_date_blocks = get_course_date_blocks(course,
                                                    request.user,
                                                    request,
                                                    num_assignments=1)
        # We will use this boolean to gate if we show a link to the dates tab. This same logic
        # dictates if we show the tab at all.
        user_enrolled = (
            request.user and request.user.is_authenticated and (bool(
                CourseEnrollment.is_enrolled(request.user, course.id)
                or has_access(request.user, 'staff', course, course.id))))

        context = {
            'course_date_blocks': [
                block for block in course_date_blocks
                if block.title != 'current_datetime'
            ],
            'dates_tab_link':
            reverse('dates', args=[course.id]),
            'user_enrolled':
            user_enrolled,
        }
        html = render_to_string(self.template_name, context)
        dates_fragment = Fragment(html)
        self.add_fragment_resource_urls(dates_fragment)

        return dates_fragment
Ejemplo n.º 2
0
    def render_to_fragment(self, request, course_id=None, **kwargs):
        """
        Render the course dates fragment.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)
        course_date_blocks = get_course_date_blocks(course,
                                                    request.user,
                                                    request,
                                                    num_assignments=2)

        context = {
            'course_date_blocks': [
                block for block in course_date_blocks
                if block.title != 'current_datetime'
            ]
        }
        html = render_to_string(self.template_name, context)
        dates_fragment = Fragment(html)
        self.add_fragment_resource_urls(dates_fragment)

        return dates_fragment
Ejemplo n.º 3
0
    def test_dates_with_openassessments(self, rubric_assessments, date_block_count):
        course = create_self_paced_course_run(days_till_start=-1, org_id='TestOrg')

        user = create_user()
        request = self.make_request(user)
        CourseEnrollmentFactory(course_id=course.id, user=user, mode=CourseMode.VERIFIED)
        now = datetime.now(utc)

        chapter = ItemFactory.create(
            parent=course,
            category="chapter",
            graded=True,
        )
        section = ItemFactory.create(
            parent=chapter,
            category="sequential",
        )
        vertical = ItemFactory.create(
            parent=section,
            category="vertical",
        )
        ItemFactory.create(
            parent=vertical,
            category="openassessment",
            rubric_assessments=rubric_assessments,
            submission_start=(now + timedelta(days=1)).isoformat(),
            submission_end=(now + timedelta(days=7)).isoformat(),
        )
        blocks = get_course_date_blocks(course, user, request, include_past_dates=True)
        assert len(blocks) == date_block_count
Ejemplo n.º 4
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)

        if course_home_legacy_is_active(course_key):
            raise Http404

        # Enable NR tracing for this view based on course
        monitoring_utils.set_custom_attribute('course_id', course_key_string)
        monitoring_utils.set_custom_attribute('user_id', request.user.id)
        monitoring_utils.set_custom_attribute('is_staff',
                                              request.user.is_staff)

        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)
        is_staff = bool(has_access(request.user, 'staff', course_key))

        _, request.user = setup_masquerade(
            request,
            course_key,
            staff_access=is_staff,
            reset_masquerade_data=True,
        )

        if not CourseEnrollment.is_enrolled(request.user,
                                            course_key) and not is_staff:
            return Response('User not enrolled.', status=401)

        blocks = get_course_date_blocks(course,
                                        request.user,
                                        request,
                                        include_access=True,
                                        include_past_dates=True)

        learner_is_full_access = not ContentTypeGatingConfig.enabled_for_enrollment(
            user=request.user,
            course_key=course_key,
        )

        # User locale settings
        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        data = {
            'has_ended':
            course.has_ended(),
            'course_date_blocks':
            [block for block in blocks if not isinstance(block, TodaysDate)],
            'learner_is_full_access':
            learner_is_full_access,
            'user_timezone':
            user_timezone,
        }
        context = self.get_serializer_context()
        context['learner_is_full_access'] = learner_is_full_access
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Ejemplo n.º 5
0
    def render_to_fragment(self, request, course_id=None, **kwargs):  # lint-amnesty, pylint: disable=arguments-differ
        """
        Render the course dates fragment.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)
        course_date_blocks = get_course_date_blocks(course,
                                                    request.user,
                                                    request,
                                                    num_assignments=1)

        dates_tab_enabled = DatesTab.is_enabled(course, request.user)
        dates_tab_link = get_learning_mfe_home_url(course_key=course.id,
                                                   url_fragment='dates')

        context = {
            'course_date_blocks': [
                block for block in course_date_blocks
                if block.title != 'current_datetime'
            ],
            'dates_tab_link':
            dates_tab_link,
            'dates_tab_enabled':
            dates_tab_enabled,
        }
        html = render_to_string(self.template_name, context)
        dates_fragment = Fragment(html)
        self.add_fragment_resource_urls(dates_fragment)

        return dates_fragment
    def render_to_fragment(self, request, course_id, user_access, **kwargs):
        """
        Renders a course message fragment for the specified course.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user, 'load', course_key)

        # Get time until the start date, if already started, or no start date, value will be zero or negative
        now = datetime.now(UTC)
        already_started = course.start and now > course.start
        days_until_start_string = "started" if already_started else format_timedelta(
            course.start - now, locale=to_locale(get_language())
        )
        course_start_data = {
            'course_start_date': format_date(course.start, locale=to_locale(get_language())),
            'already_started': already_started,
            'days_until_start_string': days_until_start_string
        }

        # Register the course home messages to be loaded on the page
        _register_course_home_messages(request, course, user_access, course_start_data)

        # Register course date alerts
        for course_date_block in get_course_date_blocks(course, request.user, request):
            course_date_block.register_alerts(request, course)

        # Register a course goal message, if appropriate
        # Only show the set course goal message for enrolled, unverified
        # users that have not yet set a goal in a course that allows for
        # verified statuses.
        user_goal = get_course_goal(auth.get_user(request), course_key)
        is_already_verified = CourseEnrollment.is_enrolled_as_verified(request.user, course_key)
        if has_course_goal_permission(request, course_id, user_access) and not is_already_verified and not user_goal:
            _register_course_goal_message(request, course)

        # Grab the relevant messages
        course_home_messages = list(CourseHomeMessages.user_messages(request))

        # Pass in the url used to set a course goal
        goal_api_url = get_goal_api_url(request)

        # Grab the logo
        image_src = 'course_experience/images/home_message_author.png'

        context = {
            'course_home_messages': course_home_messages,
            'goal_api_url': goal_api_url,
            'image_src': image_src,
            'course_id': course_id,
            'username': request.user.username,
        }

        html = render_to_string('course_experience/course-messages-fragment.html', context)
        return Fragment(html)
Ejemplo n.º 7
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)

        if not course_home_mfe_dates_tab_is_active(course_key):
            return Response(status=status.HTTP_404_NOT_FOUND)

        # Enable NR tracing for this view based on course
        monitoring_utils.set_custom_metric('course_id', course_key_string)
        monitoring_utils.set_custom_metric('user_id', request.user.id)
        monitoring_utils.set_custom_metric('is_staff', request.user.is_staff)

        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)
        blocks = get_course_date_blocks(course,
                                        request.user,
                                        request,
                                        include_access=True,
                                        include_past_dates=True)
        missed_deadlines, missed_gated_content = dates_banner_should_display(
            course_key, request.user)

        learner_is_full_access = not ContentTypeGatingConfig.enabled_for_enrollment(
            user=request.user,
            course_key=course_key,
        )

        # User locale settings
        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        data = {
            'has_ended':
            course.has_ended(),
            'course_date_blocks':
            [block for block in blocks if not isinstance(block, TodaysDate)],
            'missed_deadlines':
            missed_deadlines,
            'missed_gated_content':
            missed_gated_content,
            'learner_is_full_access':
            learner_is_full_access,
            'user_timezone':
            user_timezone,
            'verified_upgrade_link':
            verified_upgrade_deadline_link(request.user, course=course),
        }
        context = self.get_serializer_context()
        context['learner_is_full_access'] = learner_is_full_access
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Ejemplo n.º 8
0
    def render_to_fragment(self, request, course_id=None, **kwargs):
        """
        Render the course dates fragment.
        """
        from lms.urls import RESET_COURSE_DEADLINES_NAME
        from openedx.features.course_experience.urls import COURSE_DATES_FRAGMENT_VIEW_NAME

        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)
        course_date_blocks = get_course_date_blocks(course,
                                                    request.user,
                                                    request,
                                                    num_assignments=2)

        display_reset_dates_banner = False

        if RELATIVE_DATES_FLAG.is_enabled(course.id):
            display_reset_dates_banner = reset_deadlines_banner_should_display(
                course_key, request)

        reset_deadlines_url = reverse(RESET_COURSE_DEADLINES_NAME
                                      ) if display_reset_dates_banner else None

        reset_deadlines_redirect_url_base = COURSE_DATES_FRAGMENT_VIEW_NAME if (
            reset_deadlines_url) else None

        context = {
            'course_date_blocks': [
                block for block in course_date_blocks
                if block.title != 'current_datetime'
            ],
            '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': course_id
            }
        }
        html = render_to_string(self.template_name, context)
        dates_fragment = Fragment(html)
        self.add_fragment_resource_urls(dates_fragment)

        return dates_fragment
Ejemplo n.º 9
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')

        # Enable NR tracing for this view based on course
        monitoring_utils.set_custom_metric('course_id', course_key_string)
        monitoring_utils.set_custom_metric('user_id', request.user.id)
        monitoring_utils.set_custom_metric('is_staff', request.user.is_staff)

        course_key = CourseKey.from_string(course_key_string)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)
        blocks = get_course_date_blocks(course,
                                        request.user,
                                        request,
                                        include_access=True,
                                        include_past_dates=True)
        display_reset_dates_text, _ = dates_banner_should_display(
            course_key, request)

        learner_is_verified = False
        enrollment = get_enrollment(request.user.username, course_key_string)
        if enrollment:
            learner_is_verified = enrollment.get('mode') == 'verified'

        # User locale settings
        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        data = {
            'course_date_blocks':
            [block for block in blocks if not isinstance(block, TodaysDate)],
            'display_reset_dates_text':
            display_reset_dates_text,
            'learner_is_verified':
            learner_is_verified,
            'user_timezone':
            user_timezone,
            'verified_upgrade_link':
            verified_upgrade_deadline_link(request.user, course=course),
        }
        context = self.get_serializer_context()
        context['learner_is_verified'] = learner_is_verified
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Ejemplo n.º 10
0
    def render_to_fragment(self, request, course_id=None, **kwargs):
        """
        Render the course dates fragment.
        """
        course_key = CourseKey.from_string(course_id)
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)
        course_date_blocks = get_course_date_blocks(course,
                                                    request.user,
                                                    request,
                                                    num_assignments=1)

        dates_tab_enabled = DatesTab.is_enabled(course, request.user)
        if course_home_mfe_dates_tab_is_active(course_key):
            dates_tab_link = get_microfrontend_url(course_key=course.id,
                                                   view_name='dates')
        else:
            dates_tab_link = reverse('dates', args=[course.id])

        context = {
            'course_date_blocks': [
                block for block in course_date_blocks
                if block.title != 'current_datetime'
            ],
            'dates_tab_link':
            dates_tab_link,
            'dates_tab_enabled':
            dates_tab_enabled,
        }
        html = render_to_string(self.template_name, context)
        dates_fragment = Fragment(html)
        self.add_fragment_resource_urls(dates_fragment)

        return dates_fragment
Ejemplo n.º 11
0
 def assert_block_types(self, course, user, expected_blocks):
     """Assert that the enabled block types for this course are as expected."""
     blocks = get_course_date_blocks(course, user)
     assert len(blocks) == len(expected_blocks)
     assert {type(b) for b in blocks} == set(expected_blocks)
Ejemplo n.º 12
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)
        course_usage_key = modulestore().make_course_usage_key(course_key)

        if not course_home_mfe_outline_tab_is_active(course_key):
            raise Http404

        # Enable NR tracing for this view based on course
        monitoring_utils.set_custom_metric('course_id', course_key_string)
        monitoring_utils.set_custom_metric('user_id', request.user.id)
        monitoring_utils.set_custom_metric('is_staff', request.user.is_staff)

        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)

        _masquerade, request.user = setup_masquerade(
            request,
            course_key,
            staff_access=has_access(request.user, 'staff', course_key),
            reset_masquerade_data=True,
        )

        course_overview = CourseOverview.get_from_id(course_key)
        enrollment = CourseEnrollment.get_enrollment(request.user, course_key)
        allow_anonymous = COURSE_ENABLE_UNENROLLED_ACCESS_FLAG.is_enabled(
            course_key)
        allow_public = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC
        is_enrolled = enrollment and enrollment.is_active
        is_staff = has_access(request.user, 'staff', course_key)
        show_enrolled = is_enrolled or is_staff

        show_handouts = show_enrolled or allow_public
        handouts_html = get_course_info_section(
            request, request.user, course, 'handouts') if show_handouts else ''

        # TODO: TNL-7185 Legacy: Refactor to return the offer & expired data and format the message in the MFE
        offer_html = generate_offer_html(request.user, course_overview)
        course_expired_html = generate_course_expired_message(
            request.user, course_overview)

        welcome_message_html = None
        if get_course_tag(request.user, course_key, PREFERENCE_KEY) != 'False':
            if LATEST_UPDATE_FLAG.is_enabled(course_key):
                welcome_message_html = LatestUpdateFragmentView(
                ).latest_update_html(request, course)
            else:
                welcome_message_html = WelcomeMessageFragmentView(
                ).welcome_message_html(request, course)

        enroll_alert = {
            'can_enroll': True,
            'extra_text': None,
        }
        if not show_enrolled:
            if CourseMode.is_masters_only(course_key):
                enroll_alert['can_enroll'] = False
                enroll_alert['extra_text'] = _(
                    'Please contact your degree administrator or '
                    'edX Support if you have questions.')
            elif course.invitation_only:
                enroll_alert['can_enroll'] = False

        course_tools = CourseToolsPluginManager.get_enabled_course_tools(
            request, course_key)
        date_blocks = get_course_date_blocks(course,
                                             request.user,
                                             request,
                                             num_assignments=1)

        # User locale settings
        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        dates_tab_link = request.build_absolute_uri(
            reverse('dates', args=[course.id]))
        if course_home_mfe_dates_tab_is_active(course.id):
            dates_tab_link = get_microfrontend_url(course_key=course.id,
                                                   view_name='dates')

        transformers = BlockStructureTransformers()
        transformers += get_course_block_access_transformers(request.user)
        transformers += [
            BlocksAPITransformer(None, None, depth=3),
        ]

        course_blocks = get_course_blocks(request.user,
                                          course_usage_key,
                                          transformers,
                                          include_completion=True)

        dates_widget = {
            'course_date_blocks': [
                block for block in date_blocks
                if not isinstance(block, TodaysDate)
            ],
            'dates_tab_link':
            dates_tab_link,
            'user_timezone':
            user_timezone,
        }

        data = {
            'course_blocks': course_blocks,
            'course_expired_html': course_expired_html,
            'course_tools': course_tools,
            'dates_widget': dates_widget,
            'enroll_alert': enroll_alert,
            'handouts_html': handouts_html,
            'offer_html': offer_html,
            'welcome_message_html': welcome_message_html,
        }
        context = self.get_serializer_context()
        context['course_key'] = course_key
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Ejemplo n.º 13
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)
        course_usage_key = modulestore().make_course_usage_key(course_key)

        # Enable NR tracing for this view based on course
        monitoring_utils.set_custom_metric('course_id', course_key_string)
        monitoring_utils.set_custom_metric('user_id', request.user.id)
        monitoring_utils.set_custom_metric('is_staff', request.user.is_staff)

        course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=False)

        _, request.user = setup_masquerade(
            request,
            course_key,
            staff_access=has_access(request.user, 'staff', course_key),
            reset_masquerade_data=True,
        )

        enrollment = CourseEnrollment.get_enrollment(request.user, course_key)
        allow_anonymous = COURSE_ENABLE_UNENROLLED_ACCESS_FLAG.is_enabled(course_key)
        allow_public = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC
        is_enrolled = enrollment and enrollment.is_active
        is_staff = has_access(request.user, 'staff', course_key)

        show_handouts = is_enrolled or is_staff or allow_public
        handouts_html = get_course_info_section(request, request.user, course, 'handouts') if show_handouts else ''

        welcome_message_html = None
        if get_course_tag(request.user, course_key, PREFERENCE_KEY) != 'False':
            if LATEST_UPDATE_FLAG.is_enabled(course_key):
                welcome_message_html = LatestUpdateFragmentView().latest_update_html(request, course)
            else:
                welcome_message_html = WelcomeMessageFragmentView().welcome_message_html(request, course)

        course_tools = CourseToolsPluginManager.get_enabled_course_tools(request, course_key)
        date_blocks = get_course_date_blocks(course, request.user, request, num_assignments=1)

        # User locale settings
        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        dates_tab_link = request.build_absolute_uri(reverse('dates', args=[course.id]))
        if course_home_mfe_dates_tab_is_active(course.id):
            dates_tab_link = get_microfrontend_url(course_key=course.id, view_name='dates')

        transformers = BlockStructureTransformers()
        transformers += get_course_block_access_transformers(request.user)
        transformers += [
            BlocksAPITransformer(None, None, depth=3),
        ]

        course_blocks = get_course_blocks(request.user, course_usage_key, transformers, include_completion=True)

        dates_widget = {
            'course_date_blocks': [block for block in date_blocks if not isinstance(block, TodaysDate)],
            'dates_tab_link': dates_tab_link,
            'user_timezone': user_timezone,
        }

        data = {
            'course_blocks': course_blocks,
            'course_tools': course_tools,
            'dates_widget': dates_widget,
            'handouts_html': handouts_html,
            'welcome_message_html': welcome_message_html,
        }
        context = self.get_serializer_context()
        context['course_key'] = course_key
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Ejemplo n.º 14
0
 def assert_block_types(self, course, user, expected_blocks):
     """Assert that the enabled block types for this course are as expected."""
     blocks = get_course_date_blocks(course, user)
     self.assertEqual(len(blocks), len(expected_blocks))
     self.assertEqual(set(type(b) for b in blocks), set(expected_blocks))
Ejemplo n.º 15
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)
        course_usage_key = modulestore().make_course_usage_key(course_key)

        # Enable NR tracing for this view based on course
        monitoring_utils.set_custom_metric('course_id', course_key_string)
        monitoring_utils.set_custom_metric('user_id', request.user.id)
        monitoring_utils.set_custom_metric('is_staff', request.user.is_staff)

        course_tools = CourseToolsPluginManager.get_enabled_course_tools(
            request, course_key)

        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)
        date_blocks = get_course_date_blocks(course,
                                             request.user,
                                             request,
                                             num_assignments=1)

        # User locale settings
        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        dates_tab_link = request.build_absolute_uri(
            reverse('dates', args=[course.id]))
        if course_home_mfe_dates_tab_is_active(course.id):
            dates_tab_link = get_microfrontend_url(course_key=course.id,
                                                   view_name='dates')

        transformers = BlockStructureTransformers()
        transformers += course_blocks_api.get_course_block_access_transformers(
            request.user)
        transformers += [
            BlocksAPITransformer(None, None, depth=3),
        ]

        course_blocks = get_course_blocks(request.user,
                                          course_usage_key,
                                          transformers,
                                          include_completion=True)

        dates_widget = {
            'course_date_blocks': [
                block for block in date_blocks
                if not isinstance(block, TodaysDate)
            ],
            'dates_tab_link':
            dates_tab_link,
            'user_timezone':
            user_timezone,
        }

        data = {
            'course_tools': course_tools,
            'course_blocks': course_blocks,
            'dates_widget': dates_widget,
        }
        context = self.get_serializer_context()
        context['course_key'] = course_key
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Ejemplo n.º 16
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)
        course_usage_key = modulestore().make_course_usage_key(course_key)

        if course_home_legacy_is_active(course_key):
            raise Http404

        # Enable NR tracing for this view based on course
        monitoring_utils.set_custom_attribute('course_id', course_key_string)
        monitoring_utils.set_custom_attribute('user_id', request.user.id)
        monitoring_utils.set_custom_attribute('is_staff',
                                              request.user.is_staff)

        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)

        masquerade_object, request.user = setup_masquerade(
            request,
            course_key,
            staff_access=has_access(request.user, 'staff', course_key),
            reset_masquerade_data=True,
        )

        user_is_masquerading = is_masquerading(
            request.user, course_key, course_masquerade=masquerade_object)

        course_overview = CourseOverview.get_from_id(course_key)
        enrollment = CourseEnrollment.get_enrollment(request.user, course_key)
        allow_anonymous = COURSE_ENABLE_UNENROLLED_ACCESS_FLAG.is_enabled(
            course_key)
        allow_public = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC
        allow_public_outline = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC_OUTLINE

        # User locale settings
        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        if course_home_legacy_is_active(course.id):
            dates_tab_link = request.build_absolute_uri(
                reverse('dates', args=[course.id]))
        else:
            dates_tab_link = get_learning_mfe_home_url(course_key=course.id,
                                                       view_name='dates')

        # Set all of the defaults
        access_expiration = None
        cert_data = None
        course_blocks = None
        course_goals = {'goal_options': [], 'selected_goal': None}
        course_tools = CourseToolsPluginManager.get_enabled_course_tools(
            request, course_key)
        dates_widget = {
            'course_date_blocks': [],
            'dates_tab_link': dates_tab_link,
            'user_timezone': user_timezone,
        }
        enroll_alert = {
            'can_enroll': True,
            'extra_text': None,
        }
        handouts_html = None
        offer_data = None
        resume_course = {
            'has_visited_course': False,
            'url': None,
        }
        welcome_message_html = None

        is_enrolled = enrollment and enrollment.is_active
        is_staff = bool(has_access(request.user, 'staff', course_key))
        show_enrolled = is_enrolled or is_staff
        if show_enrolled:
            course_blocks = get_course_outline_block_tree(
                request, course_key_string, request.user)
            date_blocks = get_course_date_blocks(course,
                                                 request.user,
                                                 request,
                                                 num_assignments=1)
            dates_widget['course_date_blocks'] = [
                block for block in date_blocks
                if not isinstance(block, TodaysDate)
            ]

            handouts_html = get_course_info_section(request, request.user,
                                                    course, 'handouts')
            welcome_message_html = get_current_update_for_user(request, course)

            offer_data = generate_offer_data(request.user, course_overview)
            access_expiration = get_access_expiration_data(
                request.user, course_overview)
            cert_data = get_cert_data(request.user, course,
                                      enrollment.mode) if is_enrolled else None

            # Only show the set course goal message for enrolled, unverified
            # users in a course that allows for verified statuses.
            is_already_verified = CourseEnrollment.is_enrolled_as_verified(
                request.user, course_key)
            if not is_already_verified and has_course_goal_permission(
                    request, course_key_string, {'is_enrolled': is_enrolled}):
                course_goals = {
                    'goal_options':
                    valid_course_goals_ordered(include_unsure=True),
                    'selected_goal': None
                }

                selected_goal = get_course_goal(request.user, course_key)
                if selected_goal:
                    course_goals['selected_goal'] = {
                        'key': selected_goal.goal_key,
                        'text': get_course_goal_text(selected_goal.goal_key),
                    }

            try:
                resume_block = get_key_to_last_completed_block(
                    request.user, course.id)
                resume_course['has_visited_course'] = True
                resume_path = reverse('jump_to',
                                      kwargs={
                                          'course_id': course_key_string,
                                          'location': str(resume_block)
                                      })
                resume_course['url'] = request.build_absolute_uri(resume_path)
            except UnavailableCompletionData:
                start_block = get_start_block(course_blocks)
                resume_course['url'] = start_block['lms_web_url']

        elif allow_public_outline or allow_public or user_is_masquerading:
            course_blocks = get_course_outline_block_tree(
                request, course_key_string, None)
            if allow_public or user_is_masquerading:
                handouts_html = get_course_info_section(
                    request, request.user, course, 'handouts')

        if not show_enrolled:
            if CourseMode.is_masters_only(course_key):
                enroll_alert['can_enroll'] = False
                enroll_alert['extra_text'] = _(
                    'Please contact your degree administrator or '
                    'edX Support if you have questions.')
            elif course.invitation_only:
                enroll_alert['can_enroll'] = False

        # Sometimes there are sequences returned by Course Blocks that we
        # don't actually want to show to the user, such as when a sequence is
        # composed entirely of units that the user can't access. The Learning
        # Sequences API knows how to roll this up, so we use it determine which
        # sequences we should remove from course_blocks.
        #
        # The long term goal is to remove the Course Blocks API call entirely,
        # so this is a tiny first step in that migration.
        if course_blocks and learning_sequences_api_available(
                course_key, request.user):
            user_course_outline = get_user_course_outline(
                course_key, request.user, datetime.now(tz=timezone.utc))
            available_seq_ids = {
                str(usage_key)
                for usage_key in user_course_outline.sequences
            }

            # course_blocks is a reference to the root of the course, so we go
            # through the chapters (sections) to look for sequences to remove.
            for chapter_data in course_blocks['children']:
                chapter_data['children'] = [
                    seq_data for seq_data in chapter_data['children'] if
                    (seq_data['id'] in available_seq_ids or
                     # Edge case: Sometimes we have weird course structures.
                     # We expect only sequentials here, but if there is
                     # another type, just skip it (don't filter it out).
                     seq_data['type'] != 'sequential')
                ] if 'children' in chapter_data else []

        data = {
            'access_expiration': access_expiration,
            'cert_data': cert_data,
            'course_blocks': course_blocks,
            'course_goals': course_goals,
            'course_tools': course_tools,
            'dates_widget': dates_widget,
            'enroll_alert': enroll_alert,
            'handouts_html': handouts_html,
            'has_ended': course.has_ended(),
            'offer': offer_data,
            'resume_course': resume_course,
            'welcome_message_html': welcome_message_html,
        }
        context = self.get_serializer_context()
        context['course_overview'] = course_overview
        context['enable_links'] = show_enrolled or allow_public
        context['enrollment'] = enrollment
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Ejemplo n.º 17
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)
        course_usage_key = modulestore().make_course_usage_key(course_key)

        if not course_home_mfe_outline_tab_is_active(course_key):
            raise Http404

        # Enable NR tracing for this view based on course
        monitoring_utils.set_custom_attribute('course_id', course_key_string)
        monitoring_utils.set_custom_attribute('user_id', request.user.id)
        monitoring_utils.set_custom_attribute('is_staff',
                                              request.user.is_staff)

        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)

        _masquerade, request.user = setup_masquerade(
            request,
            course_key,
            staff_access=has_access(request.user, 'staff', course_key),
            reset_masquerade_data=True,
        )

        course_overview = CourseOverview.get_from_id(course_key)
        enrollment = CourseEnrollment.get_enrollment(request.user, course_key)
        allow_anonymous = COURSE_ENABLE_UNENROLLED_ACCESS_FLAG.is_enabled(
            course_key)
        allow_public = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC
        allow_public_outline = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC_OUTLINE
        is_enrolled = enrollment and enrollment.is_active
        is_staff = bool(has_access(request.user, 'staff', course_key))
        show_enrolled = is_enrolled or is_staff

        show_handouts = show_enrolled or allow_public
        handouts_html = get_course_info_section(
            request, request.user, course, 'handouts') if show_handouts else ''

        # TODO: TNL-7185 Legacy: Refactor to return the offer & expired data and format the message in the MFE
        offer_html = show_enrolled and generate_offer_html(
            request.user, course_overview)
        course_expired_html = show_enrolled and generate_course_expired_message(
            request.user, course_overview)

        welcome_message_html = None
        if show_enrolled:
            if LATEST_UPDATE_FLAG.is_enabled(course_key):
                welcome_message_html = LatestUpdateFragmentView(
                ).latest_update_html(request, course)
            elif get_course_tag(request.user, course_key,
                                PREFERENCE_KEY) != 'False':
                welcome_message_html = WelcomeMessageFragmentView(
                ).welcome_message_html(request, course)

        enroll_alert = {
            'can_enroll': True,
            'extra_text': None,
        }
        if not show_enrolled:
            if CourseMode.is_masters_only(course_key):
                enroll_alert['can_enroll'] = False
                enroll_alert['extra_text'] = _(
                    'Please contact your degree administrator or '
                    'edX Support if you have questions.')
            elif course.invitation_only:
                enroll_alert['can_enroll'] = False

        course_tools = CourseToolsPluginManager.get_enabled_course_tools(
            request, course_key)
        date_blocks = get_course_date_blocks(course,
                                             request.user,
                                             request,
                                             num_assignments=1)

        # User locale settings
        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        dates_tab_link = request.build_absolute_uri(
            reverse('dates', args=[course.id]))
        if course_home_mfe_dates_tab_is_active(course.id):
            dates_tab_link = get_microfrontend_url(course_key=course.id,
                                                   view_name='dates')

        course_blocks = None
        if show_enrolled or allow_public or allow_public_outline:
            outline_user = request.user if show_enrolled else None
            course_blocks = get_course_outline_block_tree(
                request, course_key_string, outline_user)

        resume_course = {
            'has_visited_course': False,
            'url': None,
        }
        if show_enrolled:
            try:
                resume_block = get_key_to_last_completed_block(
                    request.user, course.id)
                resume_course['has_visited_course'] = True
            except UnavailableCompletionData:
                resume_block = course_usage_key
            resume_path = reverse('jump_to',
                                  kwargs={
                                      'course_id': course_key_string,
                                      'location': str(resume_block)
                                  })
            resume_course['url'] = request.build_absolute_uri(resume_path)

        dates_widget = {
            'course_date_blocks': [
                block for block in date_blocks
                if not isinstance(block, TodaysDate)
            ],
            'dates_tab_link':
            dates_tab_link,
            'user_timezone':
            user_timezone,
        }

        # Only show the set course goal message for enrolled, unverified
        # users in a course that allows for verified statuses.
        is_already_verified = CourseEnrollment.is_enrolled_as_verified(
            request.user, course_key)
        if (not is_already_verified and has_course_goal_permission(
                request, course_key_string, {'is_enrolled': is_enrolled})):
            course_goals = {
                'goal_options':
                valid_course_goals_ordered(include_unsure=True),
                'selected_goal': None
            }

            selected_goal = get_course_goal(request.user, course_key)
            if selected_goal:
                course_goals['selected_goal'] = {
                    'key': selected_goal.goal_key,
                    'text': get_course_goal_text(selected_goal.goal_key),
                }
        else:
            course_goals = {'goal_options': [], 'selected_goal': None}

        data = {
            'course_blocks': course_blocks,
            'course_expired_html': course_expired_html or None,
            'course_goals': course_goals,
            'course_tools': course_tools,
            'dates_widget': dates_widget,
            'enroll_alert': enroll_alert,
            'handouts_html': handouts_html or None,
            'has_ended': course.has_ended(),
            'offer_html': offer_html or None,
            'resume_course': resume_course,
            'welcome_message_html': welcome_message_html or None,
        }
        context = self.get_serializer_context()
        context['course_key'] = course_key
        context['enable_links'] = show_enrolled or allow_public
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Ejemplo n.º 18
0
    def test_enabled_block_types_with_assignments(self):  # pylint: disable=too-many-statements
        """
        Creates a course with multiple subsections to test all of the different
        cases for assignment dates showing up. Mocks out calling the edx-when
        service and then validates the correct data is set and returned.
        """
        course = create_course_run(days_till_start=-100)
        user = create_user()
        request = self.make_request(user)
        CourseEnrollmentFactory(course_id=course.id, user=user, mode=CourseMode.VERIFIED)
        now = datetime.now(utc)
        assignment_title_html = ['<a href=', '</a>']
        with self.store.bulk_operations(course.id):
            section = ItemFactory.create(category='chapter', parent_location=course.location)
            ItemFactory.create(
                category='sequential',
                display_name='Released',
                parent_location=section.location,
                start=now - timedelta(days=1),
                due=now + timedelta(days=6),
                graded=True,
                format='Homework',
            )
            ItemFactory.create(
                category='sequential',
                display_name='Not released',
                parent_location=section.location,
                start=now + timedelta(days=1),
                due=now + timedelta(days=7),
                graded=True,
                format='Homework',
            )
            ItemFactory.create(
                category='sequential',
                display_name='Third nearest assignment',
                parent_location=section.location,
                start=now + timedelta(days=1),
                due=now + timedelta(days=8),
                graded=True,
                format='Exam',
            )
            ItemFactory.create(
                category='sequential',
                display_name='Past due date',
                parent_location=section.location,
                start=now - timedelta(days=14),
                due=now - timedelta(days=7),
                graded=True,
                format='Exam',
            )
            ItemFactory.create(
                category='sequential',
                display_name='Not returned since we do not get non-graded subsections',
                parent_location=section.location,
                start=now + timedelta(days=1),
                due=now - timedelta(days=7),
                graded=False,
            )
            ItemFactory.create(
                category='sequential',
                display_name='No start date',
                parent_location=section.location,
                start=None,
                due=now + timedelta(days=9),
                graded=True,
                format='Speech',
            )
            ItemFactory.create(
                category='sequential',
                # Setting display name to None should set the assignment title to 'Assignment'
                display_name=None,
                parent_location=section.location,
                start=now - timedelta(days=14),
                due=now + timedelta(days=10),
                graded=True,
                format=None,
            )
            dummy_subsection = ItemFactory.create(category='sequential', graded=True, due=now + timedelta(days=11))

        # We are deleting this subsection right after creating it because we need to pass in a real
        # location object (dummy_subsection.location), but do not want this to exist inside of the modulestore
        with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, course.id):
            self.store.delete_item(dummy_subsection.location, user.id)

        # Standard widget case where we restrict the number of assignments.
        expected_blocks = (
            TodaysDate, CourseAssignmentDate, CourseAssignmentDate, CourseEndDate, VerificationDeadlineDate
        )
        blocks = get_course_date_blocks(course, user, request, num_assignments=2)
        assert len(blocks) == len(expected_blocks)
        assert {type(b) for b in blocks} == set(expected_blocks)
        assignment_blocks = filter(
            lambda b: isinstance(b, CourseAssignmentDate), blocks
        )
        for assignment in assignment_blocks:
            assignment_title = str(assignment.title_html) or str(assignment.title)
            assert assignment_title != 'Third nearest assignment'
            assert assignment_title != 'Past due date'
            assert assignment_title != 'Not returned since we do not get non-graded subsections'
            # checking if it is _in_ the title instead of being the title since released assignments
            # are actually links. Unreleased assignments are just the string of the title.
            if 'Released' in assignment_title:
                for html_tag in assignment_title_html:
                    assert html_tag in assignment_title
            elif assignment_title == 'Not released':
                for html_tag in assignment_title_html:
                    assert html_tag not in assignment_title

        # No restrictions on number of assignments to return
        expected_blocks = (
            CourseStartDate, TodaysDate, CourseAssignmentDate, CourseAssignmentDate, CourseAssignmentDate,
            CourseAssignmentDate, CourseAssignmentDate, CourseAssignmentDate, CourseEndDate,
            VerificationDeadlineDate
        )
        blocks = get_course_date_blocks(course, user, request, include_past_dates=True)
        assert len(blocks) == len(expected_blocks)
        assert {type(b) for b in blocks} == set(expected_blocks)
        assignment_blocks = filter(
            lambda b: isinstance(b, CourseAssignmentDate), blocks
        )
        for assignment in assignment_blocks:
            assignment_title = str(assignment.title_html) or str(assignment.title)
            assert assignment_title != 'Not returned since we do not get non-graded subsections'

            assignment_type = str(assignment.assignment_type)
            # checking if it is _in_ the title instead of being the title since released assignments
            # are actually links. Unreleased assignments are just the string of the title.
            # also checking that the assignment type is returned for graded subsections
            if 'Released' in assignment_title:
                assert assignment_type == 'Homework'
                for html_tag in assignment_title_html:
                    assert html_tag in assignment_title
            elif assignment_title == 'Not released':
                assert assignment_type == 'Homework'
                for html_tag in assignment_title_html:
                    assert html_tag not in assignment_title
            elif assignment_title == 'Third nearest assignment':
                assert assignment_type == 'Exam'
                # It's still not released
                for html_tag in assignment_title_html:
                    assert html_tag not in assignment_title
            elif 'Past due date' in assignment_title:
                assert now > assignment.date
                assert assignment_type == 'Exam'
                for html_tag in assignment_title_html:
                    assert html_tag in assignment_title
            elif 'No start date' == assignment_title:
                assert assignment_type == 'Speech'
                # Can't determine if it is released so it does not get a link
                for html_tag in assignment_title_html:
                    assert html_tag not in assignment_title
            # This is the item with no display name where we set one ourselves.
            elif 'Assignment' in assignment_title:
                assert assignment_type is None
                # Can't determine if it is released so it does not get a link
                for html_tag in assignment_title_html:
                    assert html_tag in assignment_title
Ejemplo n.º 19
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)
        course_usage_key = modulestore().make_course_usage_key(course_key)

        if not course_home_mfe_outline_tab_is_active(course_key):
            raise Http404

        # Enable NR tracing for this view based on course
        monitoring_utils.set_custom_attribute('course_id', course_key_string)
        monitoring_utils.set_custom_attribute('user_id', request.user.id)
        monitoring_utils.set_custom_attribute('is_staff',
                                              request.user.is_staff)

        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)

        masquerade_object, request.user = setup_masquerade(
            request,
            course_key,
            staff_access=has_access(request.user, 'staff', course_key),
            reset_masquerade_data=True,
        )

        user_is_masquerading = is_masquerading(
            request.user, course_key, course_masquerade=masquerade_object)

        course_overview = CourseOverview.get_from_id(course_key)
        enrollment = CourseEnrollment.get_enrollment(request.user, course_key)
        allow_anonymous = COURSE_ENABLE_UNENROLLED_ACCESS_FLAG.is_enabled(
            course_key)
        allow_public = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC
        allow_public_outline = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC_OUTLINE

        # User locale settings
        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        dates_tab_link = request.build_absolute_uri(
            reverse('dates', args=[course.id]))
        if course_home_mfe_dates_tab_is_active(course.id):
            dates_tab_link = get_learning_mfe_home_url(course_key=course.id,
                                                       view_name='dates')

        # Set all of the defaults
        access_expiration = None
        course_blocks = None
        course_goals = {'goal_options': [], 'selected_goal': None}
        course_tools = CourseToolsPluginManager.get_enabled_course_tools(
            request, course_key)
        dates_widget = {
            'course_date_blocks': [],
            'dates_tab_link': dates_tab_link,
            'user_timezone': user_timezone,
        }
        enroll_alert = {
            'can_enroll': True,
            'extra_text': None,
        }
        handouts_html = None
        offer_data = None
        resume_course = {
            'has_visited_course': False,
            'url': None,
        }
        welcome_message_html = None

        is_enrolled = enrollment and enrollment.is_active
        is_staff = bool(has_access(request.user, 'staff', course_key))
        show_enrolled = is_enrolled or is_staff
        if show_enrolled:
            course_blocks = get_course_outline_block_tree(
                request, course_key_string, request.user)
            date_blocks = get_course_date_blocks(course,
                                                 request.user,
                                                 request,
                                                 num_assignments=1)
            dates_widget['course_date_blocks'] = [
                block for block in date_blocks
                if not isinstance(block, TodaysDate)
            ]

            handouts_html = get_course_info_section(request, request.user,
                                                    course, 'handouts')
            welcome_message_html = get_current_update_for_user(request, course)

            offer_data = generate_offer_data(request.user, course_overview)
            access_expiration = get_access_expiration_data(
                request.user, course_overview)

            # Only show the set course goal message for enrolled, unverified
            # users in a course that allows for verified statuses.
            is_already_verified = CourseEnrollment.is_enrolled_as_verified(
                request.user, course_key)
            if not is_already_verified and has_course_goal_permission(
                    request, course_key_string, {'is_enrolled': is_enrolled}):
                course_goals = {
                    'goal_options':
                    valid_course_goals_ordered(include_unsure=True),
                    'selected_goal': None
                }

                selected_goal = get_course_goal(request.user, course_key)
                if selected_goal:
                    course_goals['selected_goal'] = {
                        'key': selected_goal.goal_key,
                        'text': get_course_goal_text(selected_goal.goal_key),
                    }

            try:
                resume_block = get_key_to_last_completed_block(
                    request.user, course.id)
                resume_course['has_visited_course'] = True
                resume_path = reverse('jump_to',
                                      kwargs={
                                          'course_id': course_key_string,
                                          'location': str(resume_block)
                                      })
                resume_course['url'] = request.build_absolute_uri(resume_path)
            except UnavailableCompletionData:
                start_block = get_start_block(course_blocks)
                resume_course['url'] = start_block['lms_web_url']

        elif allow_public_outline or allow_public or user_is_masquerading:
            course_blocks = get_course_outline_block_tree(
                request, course_key_string, None)
            if allow_public or user_is_masquerading:
                handouts_html = get_course_info_section(
                    request, request.user, course, 'handouts')

        if not show_enrolled:
            if CourseMode.is_masters_only(course_key):
                enroll_alert['can_enroll'] = False
                enroll_alert['extra_text'] = _(
                    'Please contact your degree administrator or '
                    'edX Support if you have questions.')
            elif course.invitation_only:
                enroll_alert['can_enroll'] = False

        data = {
            'access_expiration': access_expiration,
            'course_blocks': course_blocks,
            'course_goals': course_goals,
            'course_tools': course_tools,
            'dates_widget': dates_widget,
            'enroll_alert': enroll_alert,
            'handouts_html': handouts_html,
            'has_ended': course.has_ended(),
            'offer': offer_data,
            'resume_course': resume_course,
            'welcome_message_html': welcome_message_html,
        }
        context = self.get_serializer_context()
        context['course_overview'] = course_overview
        context['enable_links'] = show_enrolled or allow_public
        context['enrollment'] = enrollment
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
    def test_enabled_block_types_with_assignments(self):  # pylint: disable=too-many-statements
        """
        Creates a course with multiple subsections to test all of the different
        cases for assignment dates showing up. Mocks out calling the edx-when
        service and then validates the correct data is set and returned.
        """
        course = create_course_run(days_till_start=-100)
        user = create_user()
        request = RequestFactory().request()
        request.user = user
        CourseEnrollmentFactory(course_id=course.id, user=user, mode=CourseMode.VERIFIED)
        now = datetime.now(utc)
        assignment_title_html = ['<a href=', '</a>']
        with self.store.bulk_operations(course.id):
            section = ItemFactory.create(category='chapter', parent_location=course.location)
            subsection_1 = ItemFactory.create(
                category='sequential',
                display_name='Released',
                parent_location=section.location,
                start=now - timedelta(days=1),
                due=now + timedelta(days=6),
                graded=True,
            )
            subsection_2 = ItemFactory.create(
                category='sequential',
                display_name='Not released',
                parent_location=section.location,
                start=now + timedelta(days=1),
                due=now + timedelta(days=7),
                graded=True,
            )
            subsection_3 = ItemFactory.create(
                category='sequential',
                display_name='Third nearest assignment',
                parent_location=section.location,
                start=now + timedelta(days=1),
                due=now + timedelta(days=8),
                graded=True,
            )
            subsection_4 = ItemFactory.create(
                category='sequential',
                display_name='Past due date',
                parent_location=section.location,
                start=now - timedelta(days=14),
                due=now - timedelta(days=7),
                graded=True,
            )
            subsection_5 = ItemFactory.create(
                category='sequential',
                display_name='Not returned since we do not get non-graded subsections',
                parent_location=section.location,
                start=now + timedelta(days=1),
                due=now - timedelta(days=7),
                graded=False,
            )
            subsection_6 = ItemFactory.create(
                category='sequential',
                display_name='No start date',
                parent_location=section.location,
                start=None,
                due=now + timedelta(days=9),
                graded=True,
            )
            subsection_7 = ItemFactory.create(
                category='sequential',
                # Setting display name to None should set the assignment title to 'Assignment'
                display_name=None,
                parent_location=section.location,
                start=now - timedelta(days=14),
                due=now + timedelta(days=10),
                graded=True,
            )
            dummy_subsection = ItemFactory.create(category='sequential')

        with patch('lms.djangoapps.courseware.courses.get_dates_for_course') as mock_get_dates:
            mock_get_dates.return_value = {
                (subsection_1.location, 'due'): subsection_1.due,
                (subsection_1.location, 'start'): subsection_1.start,
                (subsection_2.location, 'due'): subsection_2.due,
                (subsection_2.location, 'start'): subsection_2.start,
                (subsection_3.location, 'due'): subsection_3.due,
                (subsection_3.location, 'start'): subsection_3.start,
                (subsection_4.location, 'due'): subsection_4.due,
                (subsection_4.location, 'start'): subsection_4.start,
                (subsection_5.location, 'due'): subsection_5.due,
                (subsection_5.location, 'start'): subsection_5.start,
                (subsection_6.location, 'due'): subsection_6.due,
                (subsection_7.location, 'due'): subsection_7.due,
                (subsection_7.location, 'start'): subsection_7.start,
                # Adding this in for the case where we return a block that
                # doesn't actually exist as part of the course. Should just be ignored.
                (dummy_subsection.location, 'due'): dummy_subsection.due,
            }
            # Standard widget case where we restrict the number of assignments.
            expected_blocks = (
                TodaysDate, CourseAssignmentDate, CourseAssignmentDate, CourseEndDate, VerificationDeadlineDate
            )
            blocks = get_course_date_blocks(course, user, request, num_assignments=2)
            self.assertEqual(len(blocks), len(expected_blocks))
            self.assertEqual(set(type(b) for b in blocks), set(expected_blocks))
            assignment_blocks = filter(lambda b: isinstance(b, CourseAssignmentDate), blocks)
            for assignment in assignment_blocks:
                assignment_title = str(assignment.title_html) or str(assignment.title)
                self.assertNotEqual(assignment_title, 'Third nearest assignment')
                self.assertNotEqual(assignment_title, 'Past due date')
                self.assertNotEqual(assignment_title, 'Not returned since we do not get non-graded subsections')
                # checking if it is _in_ the title instead of being the title since released assignments
                # are actually links. Unreleased assignments are just the string of the title.
                if 'Released' in assignment_title:
                    for html_tag in assignment_title_html:
                        self.assertIn(html_tag, assignment_title)
                elif assignment_title == 'Not released':
                    for html_tag in assignment_title_html:
                        self.assertNotIn(html_tag, assignment_title)

            # No restrictions on number of assignments to return
            expected_blocks = (
                CourseStartDate, TodaysDate, CourseAssignmentDate, CourseAssignmentDate, CourseAssignmentDate,
                CourseAssignmentDate, CourseAssignmentDate, CourseAssignmentDate, CourseEndDate,
                VerificationDeadlineDate
            )
            blocks = get_course_date_blocks(course, user, request, include_past_dates=True)
            self.assertEqual(len(blocks), len(expected_blocks))
            self.assertEqual(set(type(b) for b in blocks), set(expected_blocks))
            assignment_blocks = filter(lambda b: isinstance(b, CourseAssignmentDate), blocks)
            for assignment in assignment_blocks:
                assignment_title = str(assignment.title_html) or str(assignment.title)
                self.assertNotEqual(assignment_title, 'Not returned since we do not get non-graded subsections')
                # checking if it is _in_ the title instead of being the title since released assignments
                # are actually links. Unreleased assignments are just the string of the title.
                if 'Released' in assignment_title:
                    for html_tag in assignment_title_html:
                        self.assertIn(html_tag, assignment_title)
                elif assignment_title == 'Not released':
                    for html_tag in assignment_title_html:
                        self.assertNotIn(html_tag, assignment_title)
                elif assignment_title == 'Third nearest assignment':
                    # It's still not released
                    for html_tag in assignment_title_html:
                        self.assertNotIn(html_tag, assignment_title)
                elif 'Past due date' in assignment_title:
                    self.assertGreater(now, assignment.date)
                    for html_tag in assignment_title_html:
                        self.assertIn(html_tag, assignment_title)
                elif 'No start date' == assignment_title:
                    # Can't determine if it is released so it does not get a link
                    for html_tag in assignment_title_html:
                        self.assertNotIn(html_tag, assignment_title)
                # This is the item with no display name where we set one ourselves.
                elif 'Assignment' in assignment_title:
                    # Can't determine if it is released so it does not get a link
                    for html_tag in assignment_title_html:
                        self.assertIn(html_tag, assignment_title)