* ENT-2294 | Moving utility functions in program enrollments to places related to the data they manipulate * updating a mock path * minor test fix
209 lines
6.9 KiB
Python
209 lines
6.9 KiB
Python
"""
|
|
Course API
|
|
"""
|
|
|
|
from __future__ import absolute_import
|
|
|
|
from edx_when.api import get_dates_for_course
|
|
from django.conf import settings
|
|
from django.contrib.auth.models import AnonymousUser, User
|
|
from django.urls import reverse
|
|
from rest_framework.exceptions import PermissionDenied
|
|
import search
|
|
import six
|
|
|
|
from lms.djangoapps.courseware.access import has_access
|
|
from lms.djangoapps.courseware.courses import (
|
|
get_course_overview_with_access,
|
|
get_courses,
|
|
get_permission_for_course_about
|
|
)
|
|
from openedx.core.lib.api.view_utils import LazySequence
|
|
from xmodule.modulestore.django import modulestore
|
|
|
|
from .permissions import can_view_courses_for_username
|
|
|
|
|
|
def get_effective_user(requesting_user, target_username):
|
|
"""
|
|
Get the user we want to view information on behalf of.
|
|
"""
|
|
if target_username == requesting_user.username:
|
|
return requesting_user
|
|
elif target_username == '':
|
|
return AnonymousUser()
|
|
elif can_view_courses_for_username(requesting_user, target_username):
|
|
return User.objects.get(username=target_username)
|
|
else:
|
|
raise PermissionDenied()
|
|
|
|
|
|
def course_detail(request, username, course_key):
|
|
"""
|
|
Return a single course identified by `course_key`.
|
|
|
|
The course must be visible to the user identified by `username` and the
|
|
logged-in user should have permission to view courses available to that
|
|
user.
|
|
|
|
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 `requesting_user would like to be identified as.
|
|
course_key (CourseKey): Identifies the course of interest
|
|
|
|
Return value:
|
|
`CourseOverview` object representing the requested course
|
|
"""
|
|
user = get_effective_user(request.user, username)
|
|
return get_course_overview_with_access(
|
|
user,
|
|
get_permission_for_course_about(),
|
|
course_key,
|
|
)
|
|
|
|
|
|
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 _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 six.text_type(course.id) in search_courses_ids
|
|
),
|
|
est_len=len(course_queryset)
|
|
)
|
|
|
|
|
|
def list_courses(request, username, org=None, roles=None, filter_=None, search_term=None):
|
|
"""
|
|
Yield all available courses.
|
|
|
|
The courses returned are all be visible to the user identified by
|
|
`username` and the logged in user should have permission to view courses
|
|
available to that user.
|
|
|
|
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:
|
|
org (string):
|
|
If specified, visible `CourseOverview` objects are filtered
|
|
such that only those belonging to the organization with the provided
|
|
org code (e.g., "HarvardX") are returned. Case-insensitive.
|
|
roles (list of strings):
|
|
If specified, visible `CourseOverview` objects are filtered
|
|
such that only those for which the user has the specified role(s)
|
|
are returned. Multiple role parameters can be specified.
|
|
filter_ (dict):
|
|
If specified, visible `CourseOverview` objects are filtered
|
|
by the given key-value pairs.
|
|
search_term (string):
|
|
Search term to filter courses (used by ElasticSearch).
|
|
|
|
Return value:
|
|
Yield `CourseOverview` objects representing the collection of courses.
|
|
"""
|
|
user = get_effective_user(request.user, username)
|
|
course_qs = get_courses(user, org=org, filter_=filter_)
|
|
course_qs = _filter_by_role(course_qs, user, roles)
|
|
course_qs = _filter_by_search(course_qs, search_term)
|
|
return course_qs
|
|
|
|
|
|
def get_due_dates(request, course_key, user):
|
|
"""
|
|
Get due date information for a user for blocks in a course.
|
|
|
|
Arguments:
|
|
request: the request object
|
|
course_key (CourseKey): the CourseKey for the course
|
|
user: the user object for which we want due date information
|
|
|
|
Returns:
|
|
due_dates (list): a list of dictionaries containing due date information
|
|
keys:
|
|
name: the display name of the block
|
|
url: the deep link to the block
|
|
date: the due date for the block
|
|
"""
|
|
dates = get_dates_for_course(
|
|
course_key,
|
|
user,
|
|
)
|
|
|
|
store = modulestore()
|
|
|
|
due_dates = []
|
|
for (block_key, date_type), date in six.iteritems(dates):
|
|
if date_type == 'due':
|
|
block = store.get_item(block_key)
|
|
|
|
# get url to the block in the course
|
|
block_url = reverse('jump_to', args=[course_key, block_key])
|
|
block_url = request.build_absolute_uri(block_url)
|
|
|
|
due_dates.append({
|
|
'name': block.display_name,
|
|
'url': block_url,
|
|
'date': date,
|
|
})
|
|
return due_dates
|
|
|
|
|
|
def get_course_run_url(request, course_id):
|
|
"""
|
|
Get the URL to a course run.
|
|
|
|
Arguments:
|
|
request: the request object
|
|
course_id (string): the course id of the course
|
|
|
|
Returns:
|
|
(string): the URL to the course run associated with course_id
|
|
"""
|
|
course_run_url = reverse('openedx.course_experience.course_home', args=[course_id])
|
|
return request.build_absolute_uri(course_run_url)
|