Files
edx-platform/openedx/core/djangoapps/credit/services.py
Dillon Dumesnil 89c463ff29 refactor: Switch to using course_overview start and end everywhere
In DE-1822, we believed we needed to switch to start_date and end_date.
It was determined this was not the case, so this updates the comment
to ensure future users use the correct fields (start and end) and
updates any pieces of code that may have used start_date or end_date.
2021-05-06 16:42:10 -04:00

215 lines
7.3 KiB
Python

"""
Implementation of "credit" XBlock service
"""
import logging
from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user
from django.core.exceptions import ObjectDoesNotExist
from opaque_keys.edx.keys import CourseKey
from common.djangoapps.student.models import CourseEnrollment
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
log = logging.getLogger(__name__)
def _get_course_key(course_key_or_id):
"""
Helper method to get a course key eith from a string or a CourseKey,
where the CourseKey will simply be returned
"""
return (
CourseKey.from_string(course_key_or_id)
if isinstance(course_key_or_id, str)
else course_key_or_id
)
class CreditService:
"""
Course Credit XBlock service
"""
def is_credit_course(self, course_key_or_id):
"""
Returns boolean if the passed in course_id (string) or course_key is
a credit_course
"""
# This seems to need to be here otherwise we get
# circular references when starting up the app
from openedx.core.djangoapps.credit.api.eligibility import (
is_credit_course,
)
course_key = _get_course_key(course_key_or_id)
return is_credit_course(course_key)
def get_credit_state(self, user_id, course_key_or_id, return_course_info=False):
"""
Return all information about the user's credit state inside of a given
course.
ARGS:
- user_id: The PK of the User in question
- course_key: The course ID (as string or CourseKey)
RETURNS:
NONE (user not found or is not enrolled or is not credit course)
- or -
{
'enrollment_mode': the mode that the user is enrolled in the course
'profile_fullname': the name that the student registered under, used for verification
'is_credit_course': if the course has been marked as a credit bearing course
'credit_requirement_status': the user's status in fulfilling those requirements
'course_name': optional display name of the course
'course_end_date': optional end date of the course
}
"""
# This seems to need to be here otherwise we get
# circular references when starting up the app
from openedx.core.djangoapps.credit.api.eligibility import (
is_credit_course,
get_credit_requirement_status,
)
# since we have to do name matching during various
# verifications, User must have a UserProfile
try:
user = User.objects.select_related('profile').get(id=user_id)
except ObjectDoesNotExist:
# bad user_id
return None
course_key = _get_course_key(course_key_or_id)
enrollment = CourseEnrollment.get_enrollment(user, course_key)
if not enrollment or not enrollment.is_active:
# not enrolled
return None
result = {
'enrollment_mode': enrollment.mode,
'profile_fullname': user.profile.name,
'student_email': user.email,
'is_credit_course': is_credit_course(course_key),
'credit_requirement_status': get_credit_requirement_status(course_key, user.username)
}
if return_course_info:
course_overview = CourseOverview.get_from_id(course_key)
result.update({
'course_name': course_overview.display_name,
'course_end_date': course_overview.end,
})
return result
def set_credit_requirement_status(self, user_id, course_key_or_id, req_namespace,
req_name, status="satisfied", reason=None):
"""
A simple wrapper around the method of the same name in api.eligibility.py. The only difference is
that a user_id is passed in.
For more information, see documentation on this method name in api.eligibility.py
"""
# This seems to need to be here otherwise we get
# circular references when starting up the app
from openedx.core.djangoapps.credit.api.eligibility import (
is_credit_course,
set_credit_requirement_status as api_set_credit_requirement_status
)
course_key = _get_course_key(course_key_or_id)
# quick exit, if course is not credit enabled
if not is_credit_course(course_key):
return
# always log any update activity to the credit requirements
# table. This will be to help debug any issues that might
# arise in production
log_msg = (
'set_credit_requirement_status was called with '
'user_id={user_id}, course_key_or_id={course_key_or_id} '
'req_namespace={req_namespace}, req_name={req_name}, '
'status={status}, reason={reason}'.format(
user_id=user_id,
course_key_or_id=course_key_or_id,
req_namespace=req_namespace,
req_name=req_name,
status=status,
reason=reason
)
)
log.info(log_msg)
# need to get user_name from the user object
try:
user = User.objects.get(id=user_id)
except ObjectDoesNotExist:
return None
api_set_credit_requirement_status(
user,
course_key,
req_namespace,
req_name,
status,
reason
)
def remove_credit_requirement_status(self, user_id, course_key_or_id, req_namespace, req_name):
"""
A simple wrapper around the method of the same name in
api.eligibility.py. The only difference is that a user_id
is passed in.
For more information, see documentation on this method name
in api.eligibility.py
"""
# This seems to need to be here otherwise we get
# circular references when starting up the app
from openedx.core.djangoapps.credit.api.eligibility import (
is_credit_course,
remove_credit_requirement_status as api_remove_credit_requirement_status
)
course_key = _get_course_key(course_key_or_id)
# quick exit, if course is not credit enabled
if not is_credit_course(course_key):
return
# always log any deleted activity to the credit requirements
# table. This will be to help debug any issues that might
# arise in production
log_msg = (
'remove_credit_requirement_status was called with '
'user_id={user_id}, course_key_or_id={course_key_or_id} '
'req_namespace={req_namespace}, req_name={req_name}, '.format(
user_id=user_id,
course_key_or_id=course_key_or_id,
req_namespace=req_namespace,
req_name=req_name
)
)
log.info(log_msg)
# need to get user_name from the user object
try:
user = User.objects.get(id=user_id)
except ObjectDoesNotExist:
return None
api_remove_credit_requirement_status(
user.username,
course_key,
req_namespace,
req_name
)