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