Files
edx-platform/openedx/features/course_experience/api/v1/views.py
Kyle McCormick 558d2eb52c refactor: centralize learning MFE URL-building logic (#26689)
In preparation for switching LMS/Studio over
from serving legacy courseware URLs in certain
places (for example, resume_course_url) to serving
learning micro-frontend URLs.

TNL-7796
2021-02-24 08:50:15 -05:00

153 lines
6.3 KiB
Python

"""
Views for Course Experience API.
"""
import logging
from django.conf import settings
from django.urls import reverse
from django.utils.html import format_html
from django.utils.translation import ugettext as _
from eventtracking import tracker
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.exceptions import APIException, ParseError
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.generics import RetrieveAPIView
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
from edx_rest_framework_extensions.auth.session.authentication import SessionAuthenticationAllowInactiveUser
from opaque_keys.edx.keys import CourseKey
from lms.djangoapps.course_api.api import course_detail
from lms.djangoapps.course_home_api.toggles import course_home_mfe_dates_tab_is_active
from lms.djangoapps.courseware.access import has_access
from lms.djangoapps.courseware.courses import get_course_with_access
from lms.djangoapps.courseware.masquerade import is_masquerading, setup_masquerade
from openedx.core.djangoapps.schedules.utils import reset_self_paced_schedule
from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser
from openedx.features.course_experience.api.v1.serializers import CourseDeadlinesMobileSerializer
from openedx.features.course_experience.url_helpers import get_learning_mfe_home_url
from openedx.features.course_experience.utils import dates_banner_should_display
log = logging.getLogger(__name__)
class UnableToResetDeadlines(APIException):
status_code = 400
default_detail = 'Unable to reset deadlines.'
default_code = 'unable_to_reset_deadlines'
@api_view(['POST'])
@authentication_classes((
JwtAuthentication, BearerAuthenticationAllowInactiveUser, SessionAuthenticationAllowInactiveUser,
))
@permission_classes((IsAuthenticated,))
def reset_course_deadlines(request):
"""
Set the start_date of a schedule to today, which in turn will adjust due dates for
sequentials belonging to a self paced course
Request Parameters:
course_key: course key
research_event_data: any data that should be included in the research tracking event
Example: sending the location of where the reset deadlines banner (i.e. outline-tab)
IMPORTANT NOTE: If updates are happening to the logic here, ALSO UPDATE the `reset_course_deadlines`
function in common/djangoapps/util/views.py as well.
"""
course_key = request.data.get('course_key', None)
research_event_data = request.data.get('research_event_data', {})
# If body doesnt contain 'course_key', return 400 to client.
if not course_key:
raise ParseError(_("'course_key' is required."))
try:
course_key = CourseKey.from_string(course_key)
course_masquerade, user = setup_masquerade(
request,
course_key,
has_access(request.user, 'staff', course_key)
)
missed_deadlines, missed_gated_content = dates_banner_should_display(course_key, user)
if missed_deadlines and not missed_gated_content:
reset_self_paced_schedule(user, course_key)
course_overview = course_detail(request, user.username, course_key)
# For context here, research_event_data should already contain `location` indicating
# the page/location dates were reset from and could also contain `block_id` if reset
# within courseware.
research_event_data.update({
'courserun_key': str(course_key),
'is_masquerading': is_masquerading(user, course_key, course_masquerade),
'is_staff': has_access(user, 'staff', course_key).has_access,
'org_key': course_overview.display_org_with_default,
'user_id': user.id,
})
tracker.emit('edx.ui.lms.reset_deadlines.clicked', research_event_data)
if course_home_mfe_dates_tab_is_active(course_key):
body_link = get_learning_mfe_home_url(course_key=str(course_key), view_name='dates')
else:
body_link = '{}{}'.format(settings.LMS_ROOT_URL, reverse('dates', args=[str(course_key)]))
return Response({
'body': format_html('<a href="{}">{}</a>', body_link, _('View all dates')),
'header': _('Your due dates have been successfully shifted to help you stay on track.'),
'link': body_link,
'link_text': _('View all dates'),
'message': _('Deadlines successfully reset.'),
})
except Exception as e:
log.exception(e)
raise UnableToResetDeadlines # lint-amnesty, pylint: disable=raise-missing-from
class CourseDeadlinesMobileView(RetrieveAPIView):
"""
**Use Cases**
Request course deadline info for mobile
**Example Requests**
GET api/course_experience/v1/course_deadlines_info/{course_key}
**Response Values**
Body consists of the following fields:
dates_banner_info: (obj)
missed_deadlines: (bool) Whether the user has missed any graded content deadlines for the given course.
missed_gated_content: (bool) Whether the user has missed any gated content for the given course.
content_type_gating_enabled: (bool) Whether content type gating is enabled for this enrollment.
verified_upgrade_link: (str) The URL to ecommerce IDA for purchasing the verified upgrade.
**Returns**
* 200 on success with above fields.
* 401 if the user is not authenticated.
* 404 if the course is not available or cannot be seen.
"""
authentication_classes = (
JwtAuthentication,
BearerAuthenticationAllowInactiveUser,
SessionAuthenticationAllowInactiveUser,
)
permission_classes = (IsAuthenticated,)
serializer_class = CourseDeadlinesMobileSerializer
def get(self, request, *args, **kwargs):
course_key_string = kwargs.get('course_key_string')
course_key = CourseKey.from_string(course_key_string)
# Although this course data is not used this method will return 404 if course does not exist
get_course_with_access(request.user, 'load', course_key)
serializer = self.get_serializer({})
return Response(serializer.data)