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.
This commit is contained in:
Dillon Dumesnil
2021-01-29 16:43:06 -05:00
parent c5913a58d5
commit 8c745cabbf
5 changed files with 47 additions and 23 deletions

View File

@@ -10,6 +10,7 @@ from mock import patch
from common.djangoapps.course_modes.models import CourseMode
from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.util.testing import EventTestMixin
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
@@ -18,28 +19,30 @@ from xmodule.modulestore.tests.factories import CourseFactory
@ddt.ddt
class ResetCourseDeadlinesViewTests(BaseCourseHomeTests, MasqueradeMixin):
class ResetCourseDeadlinesViewTests(EventTestMixin, BaseCourseHomeTests, MasqueradeMixin):
"""
Tests for reset deadlines endpoint.
"""
def setUp(self):
# Need to supply tracker name for the EventTestMixin. Also, EventTestMixin needs to come
# first in class inheritance so the setUp call here appropriately works
super().setUp('openedx.features.course_experience.api.v1.views.tracker')
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)
# Test body with incorrect body param
# Test body with incorrect body param (course_key is required)
response = self.client.post(reverse('course-experience-reset-course-deadlines'), {'course': self.course.id})
self.assertEqual(response.status_code, 400)
# Test body with additional incorrect body param
response = self.client.post(
reverse('course-experience-reset-course-deadlines'), {'course_key': self.course.id, 'invalid': 'value'}
)
self.assertEqual(response.status_code, 400)
self.assert_no_events_were_emitted()
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_user_id = self.user.id
student_enrollment = CourseEnrollment.enroll(self.user, course.id)
student_schedule = ScheduleFactory.create(
start_date=timezone.now() - datetime.timedelta(days=100),
@@ -61,6 +64,14 @@ class ResetCourseDeadlinesViewTests(BaseCourseHomeTests, MasqueradeMixin):
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)
self.assert_event_emitted(
'edx.ui.lms.reset_deadlines.clicked',
courserun_key=str(course.id),
is_masquerading=True,
is_staff=False,
org_key=course.org,
user_id=student_user_id,
)
def test_post_unauthenticated_user(self):
self.client.logout()

View File

@@ -7,6 +7,7 @@ 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
@@ -18,11 +19,12 @@ from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthenticat
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 setup_masquerade
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
@@ -48,22 +50,24 @@ 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."))
# If body contains params other than 'course_key', return 400 to client.
if len(request.data) > 1:
raise ParseError(_("Only 'course_key' is expected."))
try:
course_key = CourseKey.from_string(course_key)
_course_masquerade, user = setup_masquerade(
course_masquerade, user = setup_masquerade(
request,
course_key,
has_access(request.user, 'staff', course_key)
@@ -73,6 +77,19 @@ def reset_course_deadlines(request):
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:

View File

@@ -200,9 +200,8 @@ class TestCourseOutlinePage(SharedModuleStoreTestCase, MasqueradeMixin):
@ddt.data(
([CourseMode.AUDIT, CourseMode.VERIFIED], CourseMode.AUDIT, False, True),
([CourseMode.AUDIT, CourseMode.VERIFIED], CourseMode.VERIFIED, False, True),
([CourseMode.AUDIT, CourseMode.VERIFIED, CourseMode.MASTERS], CourseMode.MASTERS, False, True),
([CourseMode.PROFESSIONAL], CourseMode.PROFESSIONAL, False, True),
([CourseMode.AUDIT, CourseMode.VERIFIED], CourseMode.VERIFIED, True, False),
([CourseMode.MASTERS], CourseMode.MASTERS, False, True),
([CourseMode.PROFESSIONAL], CourseMode.PROFESSIONAL, True, True), # staff accounts should also see the banner
)
@ddt.unpack
def test_reset_course_deadlines_banner_shows_for_self_paced_course(

View File

@@ -281,13 +281,6 @@ def dates_banner_should_display(course_key, user):
if not CourseEnrollment.is_enrolled(user, course_key):
return False, False
# Don't display the banner for course staff
is_course_staff = bool(
user and course_overview and has_access(user, 'staff', course_overview, course_overview.id)
)
if is_course_staff:
return False, False
# Don't display the banner if the course has ended
if course_end_date and course_end_date < timezone.now():
return False, False

View File

@@ -151,6 +151,10 @@ class PersonalizedLearnerScheduleCallToAction:
},
'url': '{}{}'.format(settings.LMS_ROOT_URL, reverse('course-experience-reset-course-deadlines')),
},
'research_event_data': {
'block_id': str(xblock.location),
'location': '{category}-view'.format(category=xblock.category),
},
}
return cta_data