Skip to content
Snippets Groups Projects
models_api.py 5.65 KiB
Newer Older
"""
Provides Python APIs exposed from Student models.
"""
from common.djangoapps.student.models import CourseAccessRole as _CourseAccessRole
from common.djangoapps.student.models import CourseEnrollment as _CourseEnrollment
from common.djangoapps.student.models import ManualEnrollmentAudit as _ManualEnrollmentAudit
from common.djangoapps.student.models import (
    ENROLLED_TO_ENROLLED as _ENROLLED_TO_ENROLLED,
    ENROLLED_TO_UNENROLLED as _ENROLLED_TO_UNENROLLED,
    UNENROLLED_TO_ENROLLED as _UNENROLLED_TO_ENROLLED,
    UNENROLLED_TO_UNENROLLED as _UNENROLLED_TO_UNENROLLED,
    UNENROLLED_TO_ALLOWEDTOENROLL as _UNENROLLED_TO_ALLOWEDTOENROLL,
    ALLOWEDTOENROLL_TO_ENROLLED as _ALLOWEDTOENROLL_TO_ENROLLED,
    ALLOWEDTOENROLL_TO_UNENROLLED as _ALLOWEDTOENROLL_TO_UNENROLLED,
    DEFAULT_TRANSITION_STATE as _DEFAULT_TRANSITION_STATE,
)
from common.djangoapps.student.models import PendingNameChange as _PendingNameChange
from common.djangoapps.student.models import UserProfile as _UserProfile

# This is done so that if these strings change within the app, we can keep exported constants the same
ENROLLED_TO_ENROLLED = _ENROLLED_TO_ENROLLED
ENROLLED_TO_UNENROLLED = _ENROLLED_TO_UNENROLLED
UNENROLLED_TO_ENROLLED = _UNENROLLED_TO_ENROLLED
UNENROLLED_TO_UNENROLLED = _UNENROLLED_TO_UNENROLLED
UNENROLLED_TO_ALLOWEDTOENROLL = _UNENROLLED_TO_ALLOWEDTOENROLL
ALLOWEDTOENROLL_TO_ENROLLED = _ALLOWEDTOENROLL_TO_ENROLLED
ALLOWEDTOENROLL_TO_UNENROLLED = _ALLOWEDTOENROLL_TO_UNENROLLED
DEFAULT_TRANSITION_STATE = _DEFAULT_TRANSITION_STATE
log = logging.getLogger(__name__)
def create_manual_enrollment_audit(  # lint-amnesty, pylint: disable=missing-function-docstring
    enrolled_by,
    user_email,
    state_transition,
    reason,
):
    _ManualEnrollmentAudit.create_manual_enrollment_audit(
        user=enrolled_by,
        email=user_email,
        state_transition=state_transition,
        reason=reason,
        enrollment=course_enrollment,
    )


def get_course_enrollment(user, course_run_key):
    return _CourseEnrollment.get_enrollment(user, course_run_key)
    Get a user's phone number from the profile, if
    one exists. Otherwise, return None.
    """
    try:
        student = _UserProfile.objects.get(user_id=user_id)
    except _UserProfile.DoesNotExist as exception:
        log.exception(exception)
        return None
    return student.phone_number or None
def get_name(user_id):
    """
    Get a user's name from their profile, if one exists. Otherwise, return None.
    """
    try:
        student = _UserProfile.objects.get(user_id=user_id)
    except _UserProfile.DoesNotExist:
        log.exception(f'Could not find UserProfile for id {user_id}')
        return None
    return student.name or None


def get_course_access_role(user, org, course_id, role):
    """
    Get a specific CourseAccessRole object. Return None if
    it does not exist.

    Arguments:
        user: User object for the user who has access in a course
        org: the org the course is in
        course_id: the course_id of the CourseAccessRole
        role: the role type of the role
    """
    try:
        course_access_role = _CourseAccessRole.objects.get(
            user=user,
            org=org,
            course_id=course_id,
            role=role,
        )
    except _CourseAccessRole.DoesNotExist:
        log.exception('No CourseAccessRole found for user_id=%(user_id)s, org=%(org)s, '
                      'course_id=%(course_id)s, and role=%(role)s.', {
                          'user': user.id,
                          'org': org,
                          'course_id': course_id,
                          'role': role,
                      })
        return None
    return course_access_role
def get_pending_name_change(user):
    """
    Return a string representing the user's pending name change, or None if it does not exist.
    """
    try:
        pending_name_change = _PendingNameChange.objects.get(user=user)
        return pending_name_change.new_name
    except _PendingNameChange.DoesNotExist:
        return None


def do_name_change_request(user, new_name, rationale):
    """
    Create a name change request. This either updates the user's current PendingNameChange, or creates
    a new one if it doesn't exist. Returns the PendingNameChange object and a boolean describing whether
    or not a new one was created.
    """
    user_profile = _UserProfile.objects.get(user=user)
    if user_profile.name == new_name:
        log_msg = (
            'user_id={user_id} requested a name change, but the requested name is the same as'
            'their current profile name. Not taking any action.'.format(user_id=user.id)
        )
        log.warning(log_msg)
        return None, False

    pending_name_change, created = _PendingNameChange.objects.update_or_create(
        user=user,
        defaults={
            'new_name': new_name,
            'rationale': rationale
        }
    )

    return pending_name_change, created


def confirm_name_change(user, pending_name_change):
    """
    Confirm a pending name change. This updates the user's profile name and deletes the
    PendingNameChange object.
    """
    user_profile = _UserProfile.objects.get(user=user)

    # Store old name in profile metadata
    meta = user_profile.get_meta()
    if 'old_names' not in meta:
        meta['old_names'] = []
    meta['old_names'].append(
        [user_profile.name, pending_name_change.rationale, datetime.datetime.now(UTC).isoformat()]
    )
    user_profile.set_meta(meta)

    user_profile.name = pending_name_change.new_name
    user_profile.save()
    pending_name_change.delete()