Ejemplo n.º 1
0
    def get_queryset(self):
        """
        Yield courses visible to the user.
        """
        form = CourseListGetForm(self.request.query_params, initial={'requesting_user': self.request.user})
        if not form.is_valid():
            raise ValidationError(form.errors)

        db_courses = list_courses(
            self.request,
            form.cleaned_data['username'],
            org=form.cleaned_data['org'],
            filter_=form.cleaned_data['filter_'],
        )

        if not settings.FEATURES['ENABLE_COURSEWARE_SEARCH'] or not form.cleaned_data['search_term']:
            return db_courses

        search_courses = search.api.course_discovery_search(
            form.cleaned_data['search_term'],
            size=self.results_size_infinity,
        )

        search_courses_ids = {course['data']['id'] for course in search_courses['results']}

        return LazySequence(
            (
                course for course in db_courses
                if six.text_type(course.id) in search_courses_ids
            ),
            est_len=len(db_courses)
        )
def _filter_by_search(course_queryset, search_term):
    """
    Filters a course queryset by the specified search term.
    """
    if not settings.FEATURES['ENABLE_COURSEWARE_SEARCH'] or not search_term:
        return course_queryset

    # Return all the results, 10K is the maximum allowed value for ElasticSearch.
    # We should use 0 after upgrading to 1.1+:
    #   - https://github.com/elastic/elasticsearch/commit/8b0a863d427b4ebcbcfb1dcd69c996c52e7ae05e
    results_size_infinity = 10000

    search_courses = search.api.course_discovery_search(
        search_term,
        size=results_size_infinity,
    )

    search_courses_ids = {
        course['data']['id']
        for course in search_courses['results']
    }

    return LazySequence((course for course in course_queryset
                         if str(course.id) in search_courses_ids),
                        est_len=len(course_queryset))
Ejemplo n.º 3
0
def get_courses(user, org=None, filter_=None):
    """
    Return a LazySequence of courses available, optionally filtered by org code (case-insensitive).
    """
    courses = branding.get_visible_courses(
        org=org,
        filter_=filter_,
    ).prefetch_related(
        Prefetch(
            'modes',
            queryset=CourseMode.objects.exclude(mode_slug__in=CourseMode.CREDIT_MODES),
            to_attr='selectable_modes',
        ),
    ).select_related(
        'image_set'
    )

    permission_name = configuration_helpers.get_value(
        'COURSE_CATALOG_VISIBILITY_PERMISSION',
        settings.COURSE_CATALOG_VISIBILITY_PERMISSION
    )

    return LazySequence(
        (c for c in courses if has_access(user, permission_name, c)),
        est_len=courses.count()
    )
Ejemplo n.º 4
0
    def test_lazy_page_number_pagination(self):
        number_sequence = range(20)
        even_numbers_lazy_sequence = LazySequence(
            (
                number for number in number_sequence
                if (number % 2) == 0
            ),
            est_len=len(number_sequence)
        )

        expected_response = {
            'results': [10, 12, 14, 16, 18],
            'pagination': {
                'previous': 'http://testserver/endpoint?page_size=5',
                'num_pages': 2,
                'next': None,
                'count': 10}
        }

        request = RequestFactory().get('/endpoint', data={'page': 2, 'page_size': 5})
        request.query_params = {'page': 2, 'page_size': 5}

        pagination = LazyPageNumberPagination()
        pagination.max_page_size = 5
        pagination.page_size = 5
        paginated_queryset = pagination.paginate_queryset(even_numbers_lazy_sequence, request)
        paginated_response = pagination.get_paginated_response(paginated_queryset)
        self.assertDictEqual(expected_response, paginated_response.data)
Ejemplo n.º 5
0
def _filter_by_role(course_queryset, user, roles):
    """
    Filters a course queryset by the roles for which the user has access.
    """
    # Global staff have access to all courses. Filter course roles for non-global staff only.
    if not user.is_staff:
        if roles:
            for role in roles:
                # Filter the courses again to return only the courses for which the user has each specified role.
                course_queryset = LazySequence(
                    (course for course in course_queryset
                     if has_access(user, role, course.id)),
                    est_len=len(course_queryset))
    return course_queryset
Ejemplo n.º 6
0
def list_course_keys(request, username, role):
    """
    Yield all available CourseKeys for the user having the given role.

    The courses returned include those for which the user identified by
    `username` has the given role.  Additionally, the logged in user
    should have permission to view courses available to that user.

    Note: This function does not use branding to determine courses.

    Arguments:
        request (HTTPRequest):
            Used to identify the logged-in user and to instantiate the course
            module to retrieve the course about description
        username (string):
            The name of the user the logged-in user would like to be
            identified as

    Keyword Arguments:
        role (string):
            Course keys are filtered such that only those for which the
            user has the specified role are returned.

    Return value:
        Yield `CourseKey` objects representing the collection of courses.

    """
    user = get_effective_user(request.user, username)

    course_keys = CourseOverview.get_all_course_keys()

    # Global staff have access to all courses. Filter courses for non-global staff.
    if GlobalStaff().has_user(user):
        return course_keys

    return LazySequence(
        (
            course_key for course_key in course_keys
            if has_access(user, role, course_key)
        ),
        est_len=len(course_keys)
    )
Ejemplo n.º 7
0
    def test_not_found_error_for_invalid_page(self):
        number_sequence = range(20)
        even_numbers_lazy_sequence = LazySequence(
            (
                number for number in number_sequence
                if (number % 2) == 0
            ),
            est_len=len(number_sequence)
        )

        request = RequestFactory().get('/endpoint', data={'page': 3, 'page_size': 5})
        request.query_params = {'page': 3, 'page_size': 5}

        with self.assertRaises(Exception) as exc:
            pagination = LazyPageNumberPagination()
            pagination.max_page_size = 5
            pagination.page_size = 5
            paginated_queryset = pagination.paginate_queryset(even_numbers_lazy_sequence, request)
            pagination.get_paginated_response(paginated_queryset)
            self.assertIn('Invalid page', exc.exception)
Ejemplo n.º 8
0
    def test_not_found_error_for_invalid_page(self):
        number_sequence = range(20)  # lint-amnesty, pylint: disable=range-builtin-not-iterating
        even_numbers_lazy_sequence = LazySequence(
            (
                number for number in number_sequence
                if (number % 2) == 0
            ),
            est_len=len(number_sequence)
        )

        request = RequestFactory().get('/endpoint', data={'page': 3, 'page_size': 5})
        request.query_params = {'page': 3, 'page_size': 5}

        with pytest.raises(Exception) as exc:
            pagination = LazyPageNumberPagination()
            pagination.max_page_size = 5
            pagination.page_size = 5
            paginated_queryset = pagination.paginate_queryset(even_numbers_lazy_sequence, request)
            pagination.get_paginated_response(paginated_queryset)
            assert 'Invalid page' in exc.exception
Ejemplo n.º 9
0
def get_courses(user, org=None, filter_=None, batch_size=100):
    """
    Return a LazySequence of courses available, optionally filtered by org code (case-insensitive).
    """
    courses_qset = branding.get_visible_courses(
        org=org,
        filter_=filter_,
    ).select_related('image_set').prefetch_related(
        Prefetch(
            'modes',
            queryset=CourseMode.objects.exclude(
                mode_slug__in=CourseMode.CREDIT_MODES),
            to_attr='selectable_modes',
        ), )

    permission_name = configuration_helpers.get_value(
        'COURSE_CATALOG_VISIBILITY_PERMISSION',
        settings.COURSE_CATALOG_VISIBILITY_PERMISSION)
    if user.is_authenticated:
        prefetch_related_objects([user], 'roles', 'experimentdata_set')

        def with_prefetched_users():
            for courses in batch_iterator(courses_qset, batch_size=batch_size):
                prefetch_related_objects(
                    [user],
                    Prefetch(
                        'courseenrollment_set',
                        queryset=CourseEnrollment.objects.filter(
                            user=user,
                            course__in=courses).select_related('schedule')))
                for course in courses:
                    if has_access(user, permission_name, course):
                        yield course

        course_iterator = with_prefetched_users()
    else:
        course_iterator = (c for c in iterator(courses_qset)
                           if has_access(user, permission_name, c))
    return LazySequence(course_iterator, est_len=courses_qset.count())
Ejemplo n.º 10
0
def get_courses(user, org=None, filter_=None, permissions=None):
    """
    Return a LazySequence of courses available, optionally filtered by org code
    (case-insensitive) or a set of permissions to be satisfied for the specified
    user.
    """

    courses = branding.get_visible_courses(
        org=org,
        filter_=filter_,
    ).prefetch_related('modes', ).select_related('image_set')

    permissions = set(permissions or '')
    permission_name = configuration_helpers.get_value(
        'COURSE_CATALOG_VISIBILITY_PERMISSION',
        settings.COURSE_CATALOG_VISIBILITY_PERMISSION)
    permissions.add(permission_name)

    return LazySequence(
        (c
         for c in courses if all(has_access(user, p, c) for p in permissions)),
        est_len=courses.count())
def list_course_keys(request, username, role):
    """
    Yield all available CourseKeys for the user having the given role.

    The courses returned include those for which the user identified by
    `username` has the given role.  Additionally, the logged in user
    should have permission to view courses available to that user.

    Note: This function does not use branding to determine courses.

    Arguments:
        request (HTTPRequest):
            Used to identify the logged-in user and to instantiate the course
            module to retrieve the course about description
        username (string):
            The name of the user the logged-in user would like to be
            identified as

    Keyword Arguments:
        role (string):
            Course keys are filtered such that only those for which the
            user has the specified role are returned.

    Return value:
        Yield `CourseKey` objects representing the collection of courses.

    """
    user = get_effective_user(request.user, username)

    all_course_keys = CourseOverview.get_all_course_keys()

    # Global staff have access to all courses. Filter courses for non-global staff.
    if GlobalStaff().has_user(user):
        return all_course_keys

    if role == 'staff':
        # This short-circuit implementation bypasses has_access() which we think is too slow for some users when
        # evaluating staff-level course access for Insights.  Various tickets have context on this issue: CR-2487,
        # TNL-7448, DESUPPORT-416, and probably more.
        #
        # This is a simplified implementation that does not consider org-level access grants (e.g. when course_id is
        # empty).
        filtered_course_keys = (
            CourseAccessRole.objects.filter(
                user=user,
                # Having the instructor role implies staff access.
                role__in=['staff', 'instructor'],
            )
            # We need to check against CourseOverview so that we don't return any Libraries.
            .extra(tables=['course_overviews_courseoverview'],
                   where=['course_id = course_overviews_courseoverview.id'])
            # For good measure, make sure we don't return empty course IDs.
            .exclude(course_id=CourseKeyField.Empty).order_by(
                'course_id').values_list('course_id', flat=True).distinct())
    else:
        # This is the original implementation which still covers the case where role = "instructor":
        filtered_course_keys = LazySequence(
            (course_key for course_key in all_course_keys
             if has_access(user, role, course_key)),
            est_len=len(all_course_keys))
    return filtered_course_keys