Ejemplo n.º 1
0
    def test_hidden_content_with_transformer_override(self):
        """
        Tests content is hidden if the date changes after collection and
        during the transform phase (for example, by the DateOverrideTransformer).
        """
        with mock_registered_transformers(
            [DateOverrideTransformer, self.TRANSFORMER_CLASS_TO_TEST]):
            transformers = BlockStructureTransformers([
                DateOverrideTransformer(self.student),
                self.TRANSFORMER_CLASS_TO_TEST()
            ])

        block = self.get_block(1)
        block.hide_after_due = True
        update_block(block)
        set_date_for_block(self.course.id, block.location, 'due',
                           self.DueDateType.PAST_DATE)

        # Due date is in the past so some blocks are hidden
        self.assert_transform_results(
            self.student,
            self.ALL_BLOCKS - {1, 3, 4},
            blocks_with_differing_access=None,
            transformers=transformers,
        )

        # Set an override for the due date to be in the future
        set_date_for_block(self.course.id,
                           block.location,
                           'due',
                           self.DueDateType.FUTURE_DATE,
                           user=self.student)
        # this line is just to bust the cache for the user so it returns the updated date.
        get_dates_for_course(self.course.id,
                             user=self.student,
                             use_cached=False)

        # Now all blocks are returned for the student
        self.assert_transform_results(
            self.student,
            self.ALL_BLOCKS,
            blocks_with_differing_access=None,
            transformers=transformers,
        )

        # But not for a different user
        different_user = UserFactory()
        with mock_registered_transformers(
            [DateOverrideTransformer, self.TRANSFORMER_CLASS_TO_TEST]):
            transformers = BlockStructureTransformers([
                DateOverrideTransformer(different_user),
                self.TRANSFORMER_CLASS_TO_TEST()
            ])
        self.assert_transform_results(
            different_user,
            self.ALL_BLOCKS - {1, 3, 4},
            blocks_with_differing_access=None,
            transformers=transformers,
        )
Ejemplo n.º 2
0
def get_course_blocks(
    user,
    starting_block_usage_key,
    transformers=None,
    collected_block_structure=None,
    allow_start_dates_in_future=False,
    include_completion=False,
    include_has_scheduled_content=False,
):
    """
    A higher order function implemented on top of the
    block_structure.get_blocks function returning a transformed block
    structure for the given user starting at starting_block_usage_key.

    Arguments:
        user (django.contrib.auth.models.User) - User object for
            which the block structure is to be transformed.

        starting_block_usage_key (UsageKey) - Specifies the starting block
            of the block structure that is to be transformed.

        transformers (BlockStructureTransformers) - A collection of
            transformers whose transform methods are to be called.
            If None, get_course_block_access_transformers() is used.

        collected_block_structure (BlockStructureBlockData) - A
            block structure retrieved from a prior call to
            BlockStructureManager.get_collected.  Can be optionally
            provided if already available, for optimization.

    Returns:
        BlockStructureBlockData - A transformed block structure,
            starting at starting_block_usage_key, that has undergone the
            transform methods for the given user and the course
            associated with the block structure.  If using the default
            transformers, the transformed block structure will be
            exactly equivalent to the blocks that the given user has
            access.
    """
    if not transformers:
        transformers = BlockStructureTransformers(
            get_course_block_access_transformers(user))
    if include_completion:
        transformers += [BlockCompletionTransformer()]
    transformers.usage_info = CourseUsageInfo(
        starting_block_usage_key.course_key, user, allow_start_dates_in_future,
        include_has_scheduled_content)

    return get_block_structure_manager(
        starting_block_usage_key.course_key).get_transformed(
            transformers,
            starting_block_usage_key,
            collected_block_structure,
        )
Ejemplo n.º 3
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)

        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)

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

        return Response(serializer.data)
Ejemplo n.º 4
0
    def test_special_exams(self):
        """
        When the block structure transformers are set to allow users to view special exams,
        ensure that we can see the special exams and not any of the otherwise gated blocks.
        """
        self.transformers = BlockStructureTransformers(
            [self.TRANSFORMER_CLASS_TO_TEST(True)])
        self.course.enable_subsection_gating = True
        self.setup_gated_section(self.blocks['H'], self.blocks['A'])
        expected_blocks = ('course', 'A', 'B', 'C', 'ProctoredExam', 'D', 'E',
                           'PracticeExam', 'F', 'G', 'TimedExam', 'J', 'K',
                           'H', 'I')
        self.get_blocks_and_check_against_expected(self.user, expected_blocks)
        # clear the request cache to simulate a new request
        self.clear_caches()

        # this call triggers reevaluation of prerequisites fulfilled by the gating block.
        with patch('openedx.core.lib.gating.api._get_subsection_percentage',
                   Mock(return_value=100)):
            lms_gating_api.evaluate_prerequisite(
                self.course,
                Mock(location=self.blocks['A'].location),
                self.user,
            )
        self.get_blocks_and_check_against_expected(self.user, self.ALL_BLOCKS)
Ejemplo n.º 5
0
    def _map_block_usage_keys_to_display_names(cls, course_id):
        """
        Fetches all course blocks and build mapping between block usage key
        string and block display name for those ones, whoose category is equal
        to ``openassessment``.

        Args:
            course_id (string or CourseLocator instance) - id of course
            resourse
        Returns:
            dictionary, that contains mapping between block usage
            keys (locations) and block display names.
        """
        # pylint: disable=import-error

        from lms.djangoapps.course_blocks.api import get_course_blocks
        from openedx.core.djangoapps.content.block_structure.transformers import BlockStructureTransformers

        from xmodule.modulestore.django import modulestore

        store = modulestore()
        course_usage_key = store.make_course_usage_key(course_id)

        # Passing an empty block structure transformer here to avoid user access checks
        blocks = get_course_blocks(None, course_usage_key, BlockStructureTransformers())

        block_display_name_map = {}

        for block_key in blocks:
            block_type = blocks.get_xblock_field(block_key, 'category')
            if block_type == 'openassessment':
                block_display_name_map[str(block_key)] = blocks.get_xblock_field(block_key, 'display_name')

        return block_display_name_map
Ejemplo n.º 6
0
    def test_content_library(self):
        """
        Test when course has content library section.
        First test user can't see any content library section,
        and after that mock response from MySQL db.
        Check user can see mocked sections in content library.
        """
        raw_block_structure = get_course_blocks(
            self.user,
            self.course.location,
            transformers=BlockStructureTransformers(),
        )
        self.assertEqual(len(list(raw_block_structure.get_block_keys())), len(self.blocks))

        clear_course_from_cache(self.course.id)
        trans_block_structure = get_course_blocks(
            self.user,
            self.course.location,
            self.transformers,
        )

        # Should dynamically assign a block to student
        trans_keys = set(trans_block_structure.get_block_keys())
        block_key_set = self.get_block_key_set(
            self.blocks, 'course', 'chapter1', 'lesson1', 'vertical1', 'library_content1'
        )
        for key in block_key_set:
            self.assertIn(key, trans_keys)

        vertical2_selected = self.get_block_key_set(self.blocks, 'vertical2').pop() in trans_keys
        vertical3_selected = self.get_block_key_set(self.blocks, 'vertical3').pop() in trans_keys

        self.assertNotEqual(vertical2_selected, vertical3_selected)  # only one of them should be selected
        selected_vertical = 'vertical2' if vertical2_selected else 'vertical3'
        selected_child = 'html1' if vertical2_selected else 'html2'

        # Check course structure again.
        clear_course_from_cache(self.course.id)
        for i in range(5):
            trans_block_structure = get_course_blocks(
                self.user,
                self.course.location,
                self.transformers,
            )
            self.assertEqual(
                set(trans_block_structure.get_block_keys()),
                self.get_block_key_set(
                    self.blocks,
                    'course',
                    'chapter1',
                    'lesson1',
                    'vertical1',
                    'library_content1',
                    selected_vertical,
                    selected_child,
                ),
                u"Expected 'selected' equality failed in iteration {}.".format(i)
            )
Ejemplo n.º 7
0
def get_course_blocks(
        user,
        starting_block_usage_key,
        transformers=None,
        collected_block_structure=None,
):
    """
    A higher order function implemented on top of the
    block_structure.get_blocks function returning a transformed block
    structure for the given user starting at starting_block_usage_key.

    Arguments:
        user (django.contrib.auth.models.User) - User object for
            which the block structure is to be transformed.

        starting_block_usage_key (UsageKey) - Specifies the starting block
            of the block structure that is to be transformed.

        transformers (BlockStructureTransformers) - A collection of
            transformers whose transform methods are to be called.
            If None, COURSE_BLOCK_ACCESS_TRANSFORMERS is used.

        collected_block_structure (BlockStructureBlockData) - A
            block structure retrieved from a prior call to
            BlockStructureManager.get_collected.  Can be optionally
            provided if already available, for optimization.

    Returns:
        BlockStructureBlockData - A transformed block structure,
            starting at starting_block_usage_key, that has undergone the
            transform methods for the given user and the course
            associated with the block structure.  If using the default
            transformers, the transformed block structure will be
            exactly equivalent to the blocks that the given user has
            access.
    """
    if not transformers:
        transformers = BlockStructureTransformers(COURSE_BLOCK_ACCESS_TRANSFORMERS)
    transformers.usage_info = CourseUsageInfo(starting_block_usage_key.course_key, user)

    return get_block_structure_manager(starting_block_usage_key.course_key).get_transformed(
        transformers,
        starting_block_usage_key,
        collected_block_structure,
    )
Ejemplo n.º 8
0
 def setUp(self):
     super(TransformerRegistryTestMixin, self).setUp()
     self.patcher = patch(
         'openedx.core.djangoapps.content.block_structure.transformer_registry.'
         'TransformerRegistry.get_registered_transformers')
     mock_registry = self.patcher.start()
     mock_registry.return_value = {self.TRANSFORMER_CLASS_TO_TEST}
     self.transformers = BlockStructureTransformers(
         [self.TRANSFORMER_CLASS_TO_TEST()])
Ejemplo n.º 9
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)

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

        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        transformers = BlockStructureTransformers()
        transformers += course_blocks_api.get_course_block_access_transformers(
            request.user)
        transformers += [
            BlocksAPITransformer(None, None, depth=3),
        ]
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=True)
        course_blocks = get_course_blocks(request.user,
                                          course_usage_key,
                                          transformers,
                                          include_completion=True)

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

        course_grade = CourseGradeFactory().read(request.user, course)
        courseware_summary = course_grade.chapter_grades.values()

        data = {
            'course_blocks': course_blocks,
            'courseware_summary': courseware_summary,
            'enrollment_mode': enrollment_mode,
            'user_timezone': user_timezone,
        }
        context = self.get_serializer_context()
        context['staff_access'] = bool(
            has_access(request.user, 'staff', course))
        context['course_key'] = course_key
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Ejemplo n.º 10
0
    def setUp(self):
        """
        Setup course structure and create user for split test transformer test.
        """
        super(MilestonesTransformerTestCase, self).setUp()

        # Build course.
        self.course_hierarchy = self.get_course_hierarchy()
        self.blocks = self.build_course(self.course_hierarchy)
        self.course = self.blocks['course']

        # Enroll user in course.
        CourseEnrollmentFactory.create(user=self.user, course_id=self.course.id, is_active=True)

        self.transformers = BlockStructureTransformers([self.TRANSFORMER_CLASS_TO_TEST(False)])
def init_course_blocks(user, root_block_key):
    """
    Return a BlockStructure representing the course.

    Blocks must have the following attributes:

        .location
        .block_type
    """
    # pragma: no-cover
    from lms.djangoapps.course_blocks.api import get_course_block_access_transformers, get_course_blocks  # pylint: disable=import-error
    from openedx.core.djangoapps.content.block_structure.transformers import BlockStructureTransformers  # pylint: disable=import-error

    transformers = BlockStructureTransformers(
        get_course_block_access_transformers(user) +
        [AggregatorAnnotationTransformer()])

    return get_course_blocks(user, root_block_key, transformers)
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)

        # 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)

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

        transformers = BlockStructureTransformers()
        transformers += course_blocks_api.get_course_block_access_transformers(
            request.user)
        transformers += [
            BlocksAPITransformer(None, None, depth=3),
        ]
        get_course_with_access(request.user,
                               'load',
                               course_key,
                               check_if_enrolled=True)
        course_blocks = get_course_blocks(request.user,
                                          course_usage_key,
                                          transformers,
                                          include_completion=True)

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

        data = {
            'course_blocks': course_blocks,
            'enrollment_mode': enrollment_mode,
        }

        serializer = self.get_serializer(data)

        return Response(serializer.data)
Ejemplo n.º 13
0
    def setUp(self):
        super(TestBlockSerializerBase, self).setUp()

        self.user = UserFactory.create()

        blocks_api_transformer = BlocksAPITransformer(
            block_types_to_count=['video'],
            requested_student_view_data=['video'],
        )
        self.transformers = BlockStructureTransformers(
            COURSE_BLOCK_ACCESS_TRANSFORMERS + [blocks_api_transformer])
        self.block_structure = get_course_blocks(
            self.user,
            self.course.location,
            self.transformers,
        )
        self.serializer_context = {
            'request': MagicMock(),
            'block_structure': self.block_structure,
            'requested_fields': ['type'],
        }
Ejemplo n.º 14
0
    def setUp(self):
        super(TestBlockSerializerBase, self).setUp()  # lint-amnesty, pylint: disable=super-with-arguments

        self.user = UserFactory.create()

        blocks_api_transformer = BlocksAPITransformer(
            block_types_to_count=['video'],
            requested_student_view_data=['video'],
        )
        self.transformers = BlockStructureTransformers(
            get_course_block_access_transformers(self.user) + [blocks_api_transformer]
        )
        self.block_structure = get_course_blocks(
            self.user,
            self.course.location,
            self.transformers,
        )
        self.serializer_context = {
            'request': MagicMock(),
            'block_structure': self.block_structure,
            'requested_fields': ['type'],
        }
Ejemplo n.º 15
0
def get_blocks(
        request,
        usage_key,
        user=None,
        depth=None,
        nav_depth=None,
        requested_fields=None,
        block_counts=None,
        student_view_data=None,
        return_type='dict',
        block_types_filter=None,
        hide_access_denials=False,
        allow_start_dates_in_future=False,
):
    """
    Return a serialized representation of the course blocks.

    Arguments:
        request (HTTPRequest): Used for calling django reverse.
        usage_key (UsageKey): Identifies the starting block of interest.
        user (User): Optional user object for whom the blocks are being
            retrieved. If None, blocks are returned regardless of access checks.
        depth (integer or None): Identifies the depth of the tree to return
            starting at the root block.  If None, the entire tree starting at
            the root is returned.
        nav_depth (integer): Optional parameter that indicates how far deep to
            traverse into the block hierarchy before bundling all the
            descendants for navigation.
        requested_fields (list): Optional list of names of additional fields
            to return for each block.  Supported fields are listed in
            transformers.SUPPORTED_FIELDS.
        block_counts (list): Optional list of names of block types for which to
            return an aggregate count of blocks.
        student_view_data (list): Optional list of names of block types for
            which blocks to return their student_view_data.
        return_type (string): Possible values are 'dict' or 'list'. Indicates
            the format for returning the blocks.
        block_types_filter (list): Optional list of block type names used to filter
            the final result of returned blocks.
        hide_access_denials (bool): When True, filter out any blocks that were
            denied access to the user, even if they have access denial messages
            attached.
        allow_start_dates_in_future (bool): When True, will allow blocks to be
            returned that can bypass the StartDateTransformer's filter to show
            blocks with start dates in the future.
    """

    if HIDE_ACCESS_DENIALS_FLAG.is_enabled():
        hide_access_denials = True

    # create ordered list of transformers, adding BlocksAPITransformer at end.
    transformers = BlockStructureTransformers()
    if requested_fields is None:
        requested_fields = []
    include_completion = 'completion' in requested_fields
    include_effort_estimation = (EffortEstimationTransformer.EFFORT_TIME in requested_fields or
                                 EffortEstimationTransformer.EFFORT_ACTIVITIES in requested_fields)
    include_gated_sections = 'show_gated_sections' in requested_fields
    include_has_scheduled_content = 'has_scheduled_content' in requested_fields
    include_special_exams = 'special_exam_info' in requested_fields

    if user is not None:
        transformers += course_blocks_api.get_course_block_access_transformers(user)
        transformers += [
            MilestonesAndSpecialExamsTransformer(
                include_special_exams=include_special_exams,
                include_gated_sections=include_gated_sections
            ),
            HiddenContentTransformer()
        ]

    if hide_access_denials:
        transformers += [AccessDeniedMessageFilterTransformer()]

    # TODO: Remove this after REVE-52 lands and old-mobile-app traffic falls to < 5% of mobile traffic
    if is_request_from_mobile_app(request):
        transformers += [HideEmptyTransformer()]

    if include_effort_estimation:
        transformers += [EffortEstimationTransformer()]

    transformers += [
        BlocksAPITransformer(
            block_counts,
            student_view_data,
            depth,
            nav_depth
        )
    ]

    # transform
    blocks = course_blocks_api.get_course_blocks(
        user,
        usage_key,
        transformers,
        allow_start_dates_in_future=allow_start_dates_in_future,
        include_completion=include_completion,
        include_has_scheduled_content=include_has_scheduled_content
    )

    # filter blocks by types
    if block_types_filter:
        block_keys_to_remove = []
        for block_key in blocks:
            block_type = blocks.get_xblock_field(block_key, 'category')
            if block_type not in block_types_filter:
                block_keys_to_remove.append(block_key)
        for block_key in block_keys_to_remove:
            blocks.remove_block(block_key, keep_descendants=True)

    # serialize
    serializer_context = {
        'request': request,
        'block_structure': blocks,
        'requested_fields': requested_fields or [],
    }

    if return_type == 'dict':
        serializer = BlockDictSerializer(blocks, context=serializer_context, many=False)
    else:
        serializer = BlockSerializer(blocks, context=serializer_context, many=True)

    # return serialized data
    return 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 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.º 17
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_progress_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)

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

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

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

        # The block structure is used for both the course_grade and has_scheduled content fields
        # So it is called upfront and reused for optimization purposes
        collected_block_structure = get_block_structure_manager(
            course_key).get_collected()
        course_grade = CourseGradeFactory().read(
            request.user, collected_block_structure=collected_block_structure)

        # Get has_scheduled_content data
        transformers = BlockStructureTransformers()
        transformers += [start_date.StartDateTransformer()]
        usage_key = collected_block_structure.root_block_usage_key
        course_blocks = get_course_blocks(
            request.user,
            usage_key,
            transformers=transformers,
            collected_block_structure=collected_block_structure,
            include_has_scheduled_content=True)
        has_scheduled_content = course_blocks.get_xblock_field(
            usage_key, 'has_scheduled_content')

        # Get user_has_passing_grade data
        user_has_passing_grade = False
        if not request.user.is_anonymous:
            user_grade = course_grade.percent
            user_has_passing_grade = user_grade >= course.lowest_passing_grade

        descriptor = modulestore().get_course(course_key)
        grading_policy = descriptor.grading_policy
        verification_status = IDVerificationService.user_status(request.user)
        verification_link = None
        if verification_status['status'] is None or verification_status[
                'status'] == 'expired':
            verification_link = IDVerificationService.get_verify_location(
                course_id=course_key)
        elif verification_status['status'] == 'must_reverify':
            verification_link = IDVerificationService.get_verify_location(
                course_id=course_key)
        verification_data = {
            'link': verification_link,
            'status': verification_status['status'],
            'status_date': verification_status['status_date'],
        }

        data = {
            'end':
            course.end,
            'user_has_passing_grade':
            user_has_passing_grade,
            'certificate_data':
            get_cert_data(request.user, course, enrollment_mode, course_grade),
            'completion_summary':
            get_course_blocks_completion_summary(course_key, request.user),
            'course_grade':
            course_grade,
            'has_scheduled_content':
            has_scheduled_content,
            'section_scores':
            course_grade.chapter_grades.values(),
            'enrollment_mode':
            enrollment_mode,
            'grading_policy':
            grading_policy,
            'studio_url':
            get_studio_url(course, 'settings/grading'),
            'verification_data':
            verification_data,
        }
        context = self.get_serializer_context()
        context['staff_access'] = bool(
            has_access(request.user, 'staff', course))
        context['course_key'] = course_key
        serializer = self.get_serializer_class()(data, context=context)

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

        # 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)

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

        user_timezone_locale = user_timezone_locale_prefs(request)
        user_timezone = user_timezone_locale['user_timezone']

        transformers = BlockStructureTransformers()
        transformers += course_blocks_api.get_course_block_access_transformers(
            request.user)
        transformers += [
            BlocksAPITransformer(None, None, depth=3),
        ]
        course = get_course_with_access(request.user,
                                        'load',
                                        course_key,
                                        check_if_enrolled=True)

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

        course_grade = CourseGradeFactory().read(request.user, course)
        courseware_summary = course_grade.chapter_grades.values()

        verification_status = IDVerificationService.user_status(request.user)
        verification_link = None
        if verification_status['status'] is None or verification_status[
                'status'] == 'expired':
            verification_link = IDVerificationService.get_verify_location(
                course_id=course_key)
        elif verification_status['status'] == 'must_reverify':
            verification_link = IDVerificationService.get_verify_location(
                course_id=course_key)
        verification_data = {
            'link': verification_link,
            'status': verification_status['status'],
            'status_date': verification_status['status_date'],
        }

        data = {
            'certificate_data':
            get_cert_data(request.user, course, enrollment_mode, course_grade),
            'courseware_summary':
            courseware_summary,
            'credit_course_requirements':
            credit_course_requirements(course_key, request.user),
            'credit_support_url':
            CREDIT_SUPPORT_URL,
            'enrollment_mode':
            enrollment_mode,
            'studio_url':
            get_studio_url(course, 'settings/grading'),
            'user_timezone':
            user_timezone,
            'verification_data':
            verification_data,
        }
        context = self.get_serializer_context()
        context['staff_access'] = bool(
            has_access(request.user, 'staff', course))
        context['course_key'] = course_key
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
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)
        student_id = kwargs.get('student_id')

        if not course_home_mfe_progress_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)
        is_staff = bool(has_access(request.user, 'staff', course_key))

        student = self._get_student_user(request, course_key, student_id,
                                         is_staff)
        username = get_enterprise_learner_generic_name(
            request) or student.username

        course = get_course_with_access(student,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)

        course_overview = CourseOverview.get_from_id(course_key)
        enrollment = CourseEnrollment.get_enrollment(student, course_key)
        enrollment_mode = getattr(enrollment, 'mode', None)

        if not (enrollment and enrollment.is_active) and not is_staff:
            return Response('User not enrolled.', status=401)

        # The block structure is used for both the course_grade and has_scheduled content fields
        # So it is called upfront and reused for optimization purposes
        collected_block_structure = get_block_structure_manager(
            course_key).get_collected()
        course_grade = CourseGradeFactory().read(
            student, collected_block_structure=collected_block_structure)

        # recalculate course grade from visible grades (stored grade was calculated over all grades, visible or not)
        course_grade.update(visible_grades_only=True,
                            has_staff_access=is_staff)

        # Get has_scheduled_content data
        transformers = BlockStructureTransformers()
        transformers += [
            start_date.StartDateTransformer(),
            ContentTypeGateTransformer()
        ]
        usage_key = collected_block_structure.root_block_usage_key
        course_blocks = get_course_blocks(
            student,
            usage_key,
            transformers=transformers,
            collected_block_structure=collected_block_structure,
            include_has_scheduled_content=True)
        has_scheduled_content = course_blocks.get_xblock_field(
            usage_key, 'has_scheduled_content')

        # Get user_has_passing_grade data
        user_has_passing_grade = False
        if not student.is_anonymous:
            user_grade = course_grade.percent
            user_has_passing_grade = user_grade >= course.lowest_passing_grade

        descriptor = modulestore().get_course(course_key)
        grading_policy = descriptor.grading_policy
        verification_status = IDVerificationService.user_status(student)
        verification_link = None
        if verification_status['status'] is None or verification_status[
                'status'] == 'expired':
            verification_link = IDVerificationService.get_verify_location(
                course_id=course_key)
        elif verification_status['status'] == 'must_reverify':
            verification_link = IDVerificationService.get_verify_location(
                course_id=course_key)
        verification_data = {
            'link': verification_link,
            'status': verification_status['status'],
            'status_date': verification_status['status_date'],
        }

        access_expiration = get_access_expiration_data(request.user,
                                                       course_overview)

        data = {
            'access_expiration':
            access_expiration,
            'certificate_data':
            get_cert_data(student, course, enrollment_mode, course_grade),
            'completion_summary':
            get_course_blocks_completion_summary(course_key, student),
            'course_grade':
            course_grade,
            'credit_course_requirements':
            credit_course_requirements(course_key, student),
            'end':
            course.end,
            'enrollment_mode':
            enrollment_mode,
            'grading_policy':
            grading_policy,
            'has_scheduled_content':
            has_scheduled_content,
            'section_scores':
            list(course_grade.chapter_grades.values()),
            'studio_url':
            get_studio_url(course, 'settings/grading'),
            'username':
            username,
            'user_has_passing_grade':
            user_has_passing_grade,
            'verification_data':
            verification_data,
        }
        context = self.get_serializer_context()
        context['staff_access'] = is_staff
        context['course_blocks'] = course_blocks
        context['course_key'] = course_key
        # course_overview and enrollment will be used by VerifiedModeSerializer
        context['course_overview'] = course_overview
        context['enrollment'] = enrollment
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Ejemplo n.º 20
0
    def get(self, request, *args, **kwargs):
        course_key_string = kwargs.get('course_key_string')
        course_key = CourseKey.from_string(course_key_string)
        student_id = kwargs.get('student_id')
        if student_id:
            try:
                student_id = int(student_id)
            except ValueError:
                raise Http404

        if not course_home_mfe_progress_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)
        is_staff = bool(has_access(request.user, 'staff', course_key))

        if student_id is None or student_id == request.user.id:
            _, student = setup_masquerade(request,
                                          course_key,
                                          staff_access=is_staff,
                                          reset_masquerade_data=True)
        else:
            # When a student_id is passed in, we display the progress page for the user
            # with the provided user id, rather than the requesting user
            try:
                coach_access = has_ccx_coach_role(request.user, course_key)
            except CCXLocatorValidationException:
                coach_access = False

            has_access_on_students_profiles = is_staff or coach_access
            # Requesting access to a different student's profile
            if not has_access_on_students_profiles:
                raise Http404
            try:
                student = User.objects.get(id=student_id)
            except User.DoesNotExist as exc:
                raise Http404 from exc

        username = get_enterprise_learner_generic_name(
            request) or student.username

        course = get_course_with_access(student,
                                        'load',
                                        course_key,
                                        check_if_enrolled=False)

        course_overview = CourseOverview.get_from_id(course_key)
        enrollment = CourseEnrollment.get_enrollment(student, course_key)
        enrollment_mode = getattr(enrollment, 'mode', None)

        if not (enrollment and enrollment.is_active) and not is_staff:
            return Response('User not enrolled.', status=401)

        # The block structure is used for both the course_grade and has_scheduled content fields
        # So it is called upfront and reused for optimization purposes
        collected_block_structure = get_block_structure_manager(
            course_key).get_collected()
        course_grade = CourseGradeFactory().read(
            student, collected_block_structure=collected_block_structure)

        # Get has_scheduled_content data
        transformers = BlockStructureTransformers()
        transformers += [
            start_date.StartDateTransformer(),
            ContentTypeGateTransformer()
        ]
        usage_key = collected_block_structure.root_block_usage_key
        course_blocks = get_course_blocks(
            student,
            usage_key,
            transformers=transformers,
            collected_block_structure=collected_block_structure,
            include_has_scheduled_content=True)
        has_scheduled_content = course_blocks.get_xblock_field(
            usage_key, 'has_scheduled_content')

        # Get user_has_passing_grade data
        user_has_passing_grade = False
        if not student.is_anonymous:
            user_grade = course_grade.percent
            user_has_passing_grade = user_grade >= course.lowest_passing_grade

        descriptor = modulestore().get_course(course_key)
        grading_policy = descriptor.grading_policy
        verification_status = IDVerificationService.user_status(student)
        verification_link = None
        if verification_status['status'] is None or verification_status[
                'status'] == 'expired':
            verification_link = IDVerificationService.get_verify_location(
                course_id=course_key)
        elif verification_status['status'] == 'must_reverify':
            verification_link = IDVerificationService.get_verify_location(
                course_id=course_key)
        verification_data = {
            'link': verification_link,
            'status': verification_status['status'],
            'status_date': verification_status['status_date'],
        }

        data = {
            'username':
            username,
            'end':
            course.end,
            'user_has_passing_grade':
            user_has_passing_grade,
            'certificate_data':
            get_cert_data(student, course, enrollment_mode, course_grade),
            'completion_summary':
            get_course_blocks_completion_summary(course_key, student),
            'course_grade':
            course_grade,
            'has_scheduled_content':
            has_scheduled_content,
            'section_scores':
            course_grade.chapter_grades.values(),
            'enrollment_mode':
            enrollment_mode,
            'grading_policy':
            grading_policy,
            'studio_url':
            get_studio_url(course, 'settings/grading'),
            'verification_data':
            verification_data,
        }
        context = self.get_serializer_context()
        context['staff_access'] = is_staff
        context['course_blocks'] = course_blocks
        context['course_key'] = course_key
        # course_overview and enrollment will be used by VerifiedModeSerializerMixin
        context['course_overview'] = course_overview
        context['enrollment'] = enrollment
        serializer = self.get_serializer_class()(data, context=context)

        return Response(serializer.data)
Ejemplo n.º 21
0
def get_blocks(
    request,
    usage_key,
    user=None,
    depth=None,
    nav_depth=None,
    requested_fields=None,
    block_counts=None,
    student_view_data=None,
    return_type='dict',
    block_types_filter=None,
):
    """
    Return a serialized representation of the course blocks.

    Arguments:
        request (HTTPRequest): Used for calling django reverse.
        usage_key (UsageKey): Identifies the starting block of interest.
        user (User): Optional user object for whom the blocks are being
            retrieved. If None, blocks are returned regardless of access checks.
        depth (integer or None): Identifies the depth of the tree to return
            starting at the root block.  If None, the entire tree starting at
            the root is returned.
        nav_depth (integer): Optional parameter that indicates how far deep to
            traverse into the block hierarchy before bundling all the
            descendants for navigation.
        requested_fields (list): Optional list of names of additional fields
            to return for each block.  Supported fields are listed in
            transformers.SUPPORTED_FIELDS.
        block_counts (list): Optional list of names of block types for which to
            return an aggregate count of blocks.
        student_view_data (list): Optional list of names of block types for
            which blocks to return their student_view_data.
        return_type (string): Possible values are 'dict' or 'list'. Indicates
            the format for returning the blocks.
        block_types_filter (list): Optional list of block type names used to filter
            the final result of returned blocks.
    """
    # create ordered list of transformers, adding BlocksAPITransformer at end.
    transformers = BlockStructureTransformers()
    if requested_fields is None:
        requested_fields = []
    include_completion = 'completion' in requested_fields
    include_special_exams = 'special_exam_info' in requested_fields
    include_gated_sections = 'show_gated_sections' in requested_fields

    if user is not None:
        transformers += course_blocks_api.get_course_block_access_transformers(
            user)
        transformers += [
            MilestonesAndSpecialExamsTransformer(
                include_special_exams=include_special_exams,
                include_gated_sections=include_gated_sections)
        ]
        transformers += [HiddenContentTransformer()]
    transformers += [
        BlocksAPITransformer(block_counts, student_view_data, depth, nav_depth)
    ]

    if include_completion:
        transformers += [BlockCompletionTransformer()]

    # transform
    blocks = course_blocks_api.get_course_blocks(user, usage_key, transformers)

    # filter blocks by types
    if block_types_filter:
        block_keys_to_remove = []
        for block_key in blocks:
            block_type = blocks.get_xblock_field(block_key, 'category')
            if block_type not in block_types_filter:
                block_keys_to_remove.append(block_key)
        for block_key in block_keys_to_remove:
            blocks.remove_block(block_key, keep_descendants=True)

    # serialize
    serializer_context = {
        'request': request,
        'block_structure': blocks,
        'requested_fields': requested_fields or [],
    }

    if return_type == 'dict':
        serializer = BlockDictSerializer(blocks,
                                         context=serializer_context,
                                         many=False)
    else:
        serializer = BlockSerializer(blocks,
                                     context=serializer_context,
                                     many=True)

    # return serialized data
    return serializer.data
Ejemplo n.º 22
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)
def get_blocks(
        request,
        usage_key,
        user=None,
        depth=None,
        nav_depth=None,
        requested_fields=None,
        block_counts=None,
        student_view_data=None,
        return_type='dict',
        block_types_filter=None,
        hide_access_denials=False,
        allow_start_dates_in_future=False,
):
    """
    Return a serialized representation of the course blocks.

    Arguments:
        request (HTTPRequest): Used for calling django reverse.
        usage_key (UsageKey): Identifies the starting block of interest.
        user (User): Optional user object for whom the blocks are being
            retrieved. If None, blocks are returned regardless of access checks.
        depth (integer or None): Identifies the depth of the tree to return
            starting at the root block.  If None, the entire tree starting at
            the root is returned.
        nav_depth (integer): Optional parameter that indicates how far deep to
            traverse into the block hierarchy before bundling all the
            descendants for navigation.
        requested_fields (list): Optional list of names of additional fields
            to return for each block.  Supported fields are listed in
            transformers.SUPPORTED_FIELDS.
        block_counts (list): Optional list of names of block types for which to
            return an aggregate count of blocks.
        student_view_data (list): Optional list of names of block types for
            which blocks to return their student_view_data.
        return_type (string): Possible values are 'dict' or 'list'. Indicates
            the format for returning the blocks.
        block_types_filter (list): Optional list of block type names used to filter
            the final result of returned blocks.
        hide_access_denials (bool): When True, filter out any blocks that were
            denied access to the user, even if they have access denial messages
            attached.
        allow_start_dates_in_future (bool): When True, will allow blocks to be
            returned that can bypass the StartDateTransformer's filter to show
            blocks with start dates in the future.
    """

    if HIDE_ACCESS_DENIALS_FLAG.is_enabled():
        hide_access_denials = True

    # create ordered list of transformers, adding BlocksAPITransformer at end.
    transformers = BlockStructureTransformers()
    if requested_fields is None:
        requested_fields = []
    include_completion = 'completion' in requested_fields
    include_effort_estimation = (EffortEstimationTransformer.EFFORT_TIME in requested_fields or
                                 EffortEstimationTransformer.EFFORT_ACTIVITIES in requested_fields)
    include_gated_sections = 'show_gated_sections' in requested_fields
    include_has_scheduled_content = 'has_scheduled_content' in requested_fields
    include_special_exams = 'special_exam_info' in requested_fields

    if user is not None:
        transformers += course_blocks_api.get_course_block_access_transformers(user)
        transformers += [
            MilestonesAndSpecialExamsTransformer(
                include_special_exams=include_special_exams,
                include_gated_sections=include_gated_sections
            ),
            HiddenContentTransformer()
        ]

    # Note: A change to the BlockCompletionTransformer (https://github.com/edx/edx-platform/pull/27622/)
    # will be introducing a bug if hide_access_denials is True.  I'm accepting this risk because in
    # the AccessDeniedMessageFilterTransformer, there is note about deleting it and I believe it is
    # technically deprecated functionality. The only use case where hide_access_denials is True
    # (outside of explicitly setting the temporary waffle flag) is in lms/djangoapps/course_api/blocks/urls.py
    # for a v1 api that I also believe should have been deprecated and removed. When this code is removed,
    # please also remove this comment. Thanks!
    if hide_access_denials:
        transformers += [AccessDeniedMessageFilterTransformer()]

    if include_effort_estimation:
        transformers += [EffortEstimationTransformer()]

    transformers += [
        BlocksAPITransformer(
            block_counts,
            student_view_data,
            depth,
            nav_depth
        )
    ]

    # transform
    blocks = course_blocks_api.get_course_blocks(
        user,
        usage_key,
        transformers,
        allow_start_dates_in_future=allow_start_dates_in_future,
        include_completion=include_completion,
        include_has_scheduled_content=include_has_scheduled_content
    )

    # filter blocks by types
    if block_types_filter:
        block_keys_to_remove = []
        for block_key in blocks:
            block_type = blocks.get_xblock_field(block_key, 'category')
            if block_type not in block_types_filter:
                block_keys_to_remove.append(block_key)
        for block_key in block_keys_to_remove:
            blocks.remove_block(block_key, keep_descendants=True)

    # serialize
    serializer_context = {
        'request': request,
        'block_structure': blocks,
        'requested_fields': requested_fields or [],
    }

    if return_type == 'dict':
        serializer = BlockDictSerializer(blocks, context=serializer_context, many=False)
    else:
        serializer = BlockSerializer(blocks, context=serializer_context, many=True)

    # return serialized data
    return serializer.data
Ejemplo n.º 24
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)