Merge pull request #22156 from cpennington/expose-course-duration

Expose user course duration in the user metadata
This commit is contained in:
Calen Pennington
2019-10-25 13:49:14 -04:00
committed by GitHub
3 changed files with 52 additions and 20 deletions

View File

@@ -21,7 +21,7 @@ from openedx.core.djangoapps.catalog.utils import get_programs
from openedx.core.djangoapps.django_comment_common.models import Role
from openedx.core.djangoapps.schedules.models import Schedule
from openedx.core.djangoapps.waffle_utils import WaffleFlag, WaffleFlagNamespace
from openedx.features.course_duration_limits.access import get_user_course_expiration_date
from openedx.features.course_duration_limits.access import get_user_course_expiration_date, get_user_course_duration
from openedx.features.course_duration_limits.models import CourseDurationLimitConfig
from student.models import CourseEnrollment
from xmodule.partitions.partitions_service import get_all_partitions_for_course, get_user_partition_groups
@@ -324,6 +324,8 @@ def get_base_experiment_metadata_context(course, user, enrollment, user_enrollme
user, enrollment, course
)
deadline, duration = get_audit_access_expiration(user, course)
return {
'upgrade_link': upgrade_link,
'upgrade_price': six.text_type(get_cosmetic_verified_display_price(course)),
@@ -333,7 +335,8 @@ def get_base_experiment_metadata_context(course, user, enrollment, user_enrollme
'pacing_type': 'self_paced' if course.self_paced else 'instructor_paced',
'dynamic_upgrade_deadline': dynamic_upgrade_deadline,
'course_upgrade_deadline': course_upgrade_deadline,
'audit_access_deadline': get_audit_access_expiration(user, course),
'audit_access_deadline': deadline,
'course_duration': duration,
'course_key': course.id,
'course_start': course.start,
'course_end': course.end,
@@ -345,12 +348,12 @@ def get_base_experiment_metadata_context(course, user, enrollment, user_enrollme
def get_audit_access_expiration(user, course):
"""
Return the expiration date for the user's audit access to this course.
Return the expiration date and course duration for the user's audit access to this course.
"""
if not CourseDurationLimitConfig.enabled_for_enrollment(user=user, course_key=course.id):
return None
return None, None
return get_user_course_expiration_date(user, course)
return get_user_course_expiration_date(user, course), get_user_course_duration(user, course)
# TODO: clean up as part of REVEM-199 (START)

View File

@@ -16,6 +16,7 @@ user_metadata = {
'upgrade_link',
'upgrade_price',
'audit_access_deadline',
'course_duration',
'pacing_type',
'has_staff_access',
'forum_roles',
@@ -42,11 +43,19 @@ for datekey in (
'course_end',
'dynamic_upgrade_deadline',
'course_upgrade_deadline',
'audit_access_deadline',
):
user_metadata[datekey] = (
context.get(datekey).isoformat() if context.get(datekey) else None
)
for timedeltakey in (
'course_duration',
):
user_metadata[timedeltakey] = (
context.get(timedeltakey).total_seconds() if context.get(timedeltake) else None
)
course_key = context.get('course_key')
if course and not course_key:
course_key = course.id

View File

@@ -54,6 +54,39 @@ class AuditExpiredError(AccessError):
additional_context_user_message)
def get_user_course_duration(user, course):
"""
Return a timedelta measuring the duration of the course for a particular user.
Business Logic:
- Course access duration is bounded by the min and max duration.
- If course fields are missing, default course access duration to MIN_DURATION.
"""
access_duration = MIN_DURATION
verified_mode = CourseMode.verified_mode_for_course(course=course, include_expired=True)
if not verified_mode:
return None
enrollment = CourseEnrollment.get_enrollment(user, course.id)
if enrollment is None or enrollment.mode != CourseMode.AUDIT:
return None
# The user course expiration date is the content availability date
# plus the weeks_to_complete field from course-discovery.
discovery_course_details = get_course_run_details(course.id, ['weeks_to_complete'])
expected_weeks = discovery_course_details.get('weeks_to_complete')
if expected_weeks:
access_duration = timedelta(weeks=expected_weeks)
# Course access duration is bounded by the min and max duration.
access_duration = max(MIN_DURATION, min(MAX_DURATION, access_duration))
return access_duration
def get_user_course_expiration_date(user, course):
"""
Return expiration date for given user course pair.
@@ -63,11 +96,8 @@ def get_user_course_expiration_date(user, course):
- Course access duration is bounded by the min and max duration.
- If course fields are missing, default course access duration to MIN_DURATION.
"""
access_duration = MIN_DURATION
verified_mode = CourseMode.verified_mode_for_course(course=course, include_expired=True)
if not verified_mode:
access_duration = get_user_course_duration(user, course)
if access_duration is None:
return None
enrollment = CourseEnrollment.get_enrollment(user, course.id)
@@ -90,16 +120,6 @@ def get_user_course_expiration_date(user, course):
except CourseEnrollment.schedule.RelatedObjectDoesNotExist:
content_availability_date = max(enrollment.created, course.start)
# The user course expiration date is the content availability date
# plus the weeks_to_complete field from course-discovery.
discovery_course_details = get_course_run_details(course.id, ['weeks_to_complete'])
expected_weeks = discovery_course_details.get('weeks_to_complete')
if expected_weeks:
access_duration = timedelta(weeks=expected_weeks)
# Course access duration is bounded by the min and max duration.
access_duration = max(MIN_DURATION, min(MAX_DURATION, access_duration))
return content_availability_date + access_duration