Files
edx-platform/openedx/features/course_experience/api/v1/views.py
Dillon Dumesnil 8c745cabbf AA-492: Adds research tracking event for reset deadlines
This PR also removes the exemption for staff from seeing the reset
deadlines banner (staff will now see the banner). Staff users would
still be unable to submit problems and wouldn't have a way of resetting
their deadlines while enrolled.
2021-02-01 10:48:11 -05:00

153 lines
6.2 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.course_home_api.utils import get_microfrontend_url
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.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_microfrontend_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
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)