Files
edx-platform/openedx/core/djangoapps/credit/services.py
Kyle McCormick 151bd13666 Use full names for common.djangoapps imports; warn when using old style (#25477)
* Generate common/djangoapps import shims for LMS
* Generate common/djangoapps import shims for Studio
* Stop appending project root to sys.path
* Stop appending common/djangoapps to sys.path
* Import from common.djangoapps.course_action_state instead of course_action_state
* Import from common.djangoapps.course_modes instead of course_modes
* Import from common.djangoapps.database_fixups instead of database_fixups
* Import from common.djangoapps.edxmako instead of edxmako
* Import from common.djangoapps.entitlements instead of entitlements
* Import from common.djangoapps.pipline_mako instead of pipeline_mako
* Import from common.djangoapps.static_replace instead of static_replace
* Import from common.djangoapps.student instead of student
* Import from common.djangoapps.terrain instead of terrain
* Import from common.djangoapps.third_party_auth instead of third_party_auth
* Import from common.djangoapps.track instead of track
* Import from common.djangoapps.util instead of util
* Import from common.djangoapps.xblock_django instead of xblock_django
* Add empty common/djangoapps/__init__.py to fix pytest collection
* Fix pylint formatting violations
* Exclude import_shims/ directory tree from linting
2020-11-10 07:02:01 -05:00

217 lines
7.3 KiB
Python

"""
Implementation of "credit" XBlock service
"""
import logging
import six
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from opaque_keys.edx.keys import CourseKey
from common.djangoapps.student.models import CourseEnrollment
from xmodule.modulestore.django import modulestore
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, six.string_types)
else course_key_or_id
)
class CreditService(object):
"""
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 = modulestore().get_course(course_key, depth=0)
result.update({
'course_name': course.display_name,
'course_end_date': course.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 = (
u'set_credit_requirement_status was called with '
u'user_id={user_id}, course_key_or_id={course_key_or_id} '
u'req_namespace={req_namespace}, req_name={req_name}, '
u'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 = (
u'remove_credit_requirement_status was called with '
u'user_id={user_id}, course_key_or_id={course_key_or_id} '
u'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
)