Merge pull request #25897 from edx/ddumesnil/fix-masquerade-for-mfe
Fixes for Shift deadlines during masquerade in Learning MFE
This commit is contained in:
@@ -196,6 +196,9 @@ 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
|
||||
|
||||
IMPORTANT NOTE: If updates are happening to the logic here, ALSO UPDATE the `reset_course_deadlines`
|
||||
function in openedx/features/course_experience/api/v1/views.py as well.
|
||||
"""
|
||||
course_key = CourseKey.from_string(request.POST.get('course_id'))
|
||||
_course_masquerade, user = setup_masquerade(
|
||||
|
||||
@@ -1631,6 +1631,9 @@ def render_xblock(request, usage_key_string, check_if_enrolled=True):
|
||||
u"Rendering of the xblock view '{}' is not supported.".format(bleach.clean(requested_view, strip=True))
|
||||
)
|
||||
|
||||
staff_access = has_access(request.user, 'staff', course_key)
|
||||
_course_masquerade, request.user = setup_masquerade(request, course_key, staff_access)
|
||||
|
||||
with modulestore().bulk_operations(course_key):
|
||||
# verify the user has access to the course, including enrollment check
|
||||
try:
|
||||
@@ -1668,7 +1671,7 @@ def render_xblock(request, usage_key_string, check_if_enrolled=True):
|
||||
'disable_window_wrap': True,
|
||||
'enable_completion_on_view_service': enable_completion_on_view_service,
|
||||
'edx_notes_enabled': is_feature_enabled(course, request.user),
|
||||
'staff_access': bool(request.user.has_perm(VIEW_XQA_INTERFACE, course)),
|
||||
'staff_access': staff_access,
|
||||
'xqa_server': settings.FEATURES.get('XQA_SERVER', 'http://your_xqa_server.com'),
|
||||
'missed_deadlines': missed_deadlines,
|
||||
'missed_gated_content': missed_gated_content,
|
||||
|
||||
@@ -1,23 +1,29 @@
|
||||
"""
|
||||
Tests for reset deadlines endpoint.
|
||||
"""
|
||||
import datetime
|
||||
import ddt
|
||||
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from mock import patch
|
||||
|
||||
from common.djangoapps.course_modes.models import CourseMode
|
||||
from lms.djangoapps.course_home_api.tests.utils import BaseCourseHomeTests
|
||||
from common.djangoapps.student.models import CourseEnrollment
|
||||
from lms.djangoapps.courseware.tests.helpers import MasqueradeMixin
|
||||
from lms.djangoapps.course_home_api.tests.utils import BaseCourseHomeTests
|
||||
from openedx.core.djangoapps.schedules.models import Schedule
|
||||
from openedx.core.djangoapps.schedules.tests.factories import ScheduleFactory
|
||||
from xmodule.modulestore.tests.factories import CourseFactory
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ResetCourseDeadlinesViewTests(BaseCourseHomeTests):
|
||||
class ResetCourseDeadlinesViewTests(BaseCourseHomeTests, MasqueradeMixin):
|
||||
"""
|
||||
Tests for reset deadlines endpoint.
|
||||
"""
|
||||
@ddt.data(CourseMode.VERIFIED)
|
||||
def test_reset_deadlines(self, enrollment_mode):
|
||||
CourseEnrollment.enroll(self.user, self.course.id, enrollment_mode)
|
||||
def test_reset_deadlines(self):
|
||||
CourseEnrollment.enroll(self.user, self.course.id, CourseMode.VERIFIED)
|
||||
# Test correct post body
|
||||
response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': self.course.id})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -30,6 +36,32 @@ class ResetCourseDeadlinesViewTests(BaseCourseHomeTests):
|
||||
)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
def test_reset_deadlines_with_masquerade(self):
|
||||
""" Staff users should be able to masquerade as a learner and reset the learner's schedule """
|
||||
course = CourseFactory.create(self_paced=True)
|
||||
student_username = self.user.username
|
||||
student_enrollment = CourseEnrollment.enroll(self.user, course.id)
|
||||
student_schedule = ScheduleFactory.create(
|
||||
start_date=timezone.now() - datetime.timedelta(days=100),
|
||||
enrollment=student_enrollment
|
||||
)
|
||||
staff_schedule = ScheduleFactory(
|
||||
start_date=timezone.now() - datetime.timedelta(days=30),
|
||||
enrollment__course__id=course.id,
|
||||
enrollment__user=self.staff_user,
|
||||
)
|
||||
|
||||
self.switch_to_staff()
|
||||
self.update_masquerade(course=course, username=student_username)
|
||||
|
||||
with patch('openedx.features.course_experience.api.v1.views.dates_banner_should_display',
|
||||
return_value=(True, False)):
|
||||
self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': course.id})
|
||||
updated_schedule = Schedule.objects.get(id=student_schedule.id)
|
||||
self.assertEqual(updated_schedule.start_date.date(), datetime.datetime.today().date())
|
||||
updated_staff_schedule = Schedule.objects.get(id=staff_schedule.id)
|
||||
self.assertEqual(updated_staff_schedule.start_date, staff_schedule.start_date)
|
||||
|
||||
def test_post_unauthenticated_user(self):
|
||||
self.client.logout()
|
||||
response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course_key': self.course.id})
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import six
|
||||
"""
|
||||
Views for Course Experience API.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
from django.urls import reverse
|
||||
@@ -13,15 +16,20 @@ 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_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 setup_masquerade
|
||||
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
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):
|
||||
@@ -36,6 +44,13 @@ class UnableToResetDeadlines(APIException):
|
||||
))
|
||||
@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
|
||||
|
||||
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)
|
||||
|
||||
# If body doesnt contain 'course_key', return 400 to client.
|
||||
@@ -47,13 +62,21 @@ def reset_course_deadlines(request):
|
||||
raise ParseError(_("Only 'course_key' is expected."))
|
||||
|
||||
try:
|
||||
reset_self_paced_schedule(request.user, course_key)
|
||||
course_key = CourseKey.from_string(course_key)
|
||||
_course_masquerade, user = setup_masquerade(
|
||||
request,
|
||||
course_key,
|
||||
has_access(request.user, 'staff', course_key)
|
||||
)
|
||||
|
||||
key = CourseKey.from_string(course_key)
|
||||
if course_home_mfe_dates_tab_is_active(key):
|
||||
body_link = get_microfrontend_url(course_key=course_key, view_name='dates')
|
||||
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)
|
||||
|
||||
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=[six.text_type(course_key)]))
|
||||
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')),
|
||||
@@ -62,7 +85,8 @@ def reset_course_deadlines(request):
|
||||
'link_text': _('View all dates'),
|
||||
'message': _('Deadlines successfully reset.'),
|
||||
})
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
log.exception(e)
|
||||
raise UnableToResetDeadlines
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user