Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

E0d/refactor 0002 inter app apis #31547

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 150 additions & 11 deletions common/djangoapps/student/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@
"""
Python APIs exposed by the student app to other in-process apps.
"""


import datetime
import logging

from django.contrib.auth import get_user_model
from django.conf import settings
from opaque_keys.edx.keys import CourseKey
from pytz import UTC

from common.djangoapps.student.models import CourseEnrollment
from common.djangoapps.student.models_api import create_manual_enrollment_audit as _create_manual_enrollment_audit
from common.djangoapps.student.models_api import get_course_access_role
from common.djangoapps.student.models_api import get_course_enrollment as _get_course_enrollment
from common.djangoapps.student.models_api import (
from common.djangoapps.student.models import CourseEnrollment as _CourseEnrollment, UserProfile as _UserProfile, \
CourseAccessRole as _CourseAccessRole, PendingNameChange as _PendingNameChange, \
ManualEnrollmentAudit as _ManualEnrollmentAudit
Comment on lines +12 to +14
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The prevailing style in edx-platform is to have one import .... as .... per line, preferring parentheses to backslashes. The from common.djangoapps.student.models import (... on the next line is a good example.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,
Expand All @@ -30,7 +28,6 @@
GlobalStaff,
REGISTERED_ACCESS_ROLES as _REGISTERED_ACCESS_ROLES,
)
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers


# This is done so that if these strings change within the app, we can keep exported constants the same
Expand Down Expand Up @@ -59,6 +56,35 @@
log = logging.getLogger()


def _create_manual_enrollment_audit(
enrolled_by,
user_email,
state_transition,
reason,
course_enrollment
):
"""
Creates a record of a student being manually enrolled in a course via the ManualEnrollmentAudit
model. The corresponding StudentEnrollment is not created by this function.
@param enrolled_by:
@param user_email:
@param state_transition:
@param reason:
@param course_enrollment:
"""
_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)


def create_manual_enrollment_audit(
enrolled_by,
user_email,
Expand Down Expand Up @@ -88,7 +114,7 @@ def create_manual_enrollment_audit(
enrolled_user = None

if enrolled_user and course_run_key:
enrollment = _get_course_enrollment(enrolled_user, course_run_key)
enrollment = get_course_enrollment(enrolled_user, course_run_key)
else:
enrollment = None

Expand Down Expand Up @@ -119,7 +145,7 @@ def is_user_enrolled_in_course(student, course_key):
Determines if a learner is enrolled in a given course-run.
"""
log.info(f"Checking if {student.id} is enrolled in course {course_key}")
return CourseEnrollment.is_enrolled(student, course_key)
return _CourseEnrollment.is_enrolled(student, course_key)


def is_user_staff_or_instructor_in_course(user, course_key):
Expand All @@ -136,3 +162,116 @@ def is_user_staff_or_instructor_in_course(user, course_key):
CourseStaffRole(course_key).has_user(user) or
CourseInstructorRole(course_key).has_user(user)
)


def get_phone_number(user_id):
"""
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 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
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()
167 changes: 0 additions & 167 deletions common/djangoapps/student/models_api.py

This file was deleted.

2 changes: 1 addition & 1 deletion common/djangoapps/student/signals/receivers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
is_email_retired,
is_username_retired
)
from common.djangoapps.student.models_api import confirm_name_change
from common.djangoapps.student.api import confirm_name_change
from common.djangoapps.student.signals import USER_EMAIL_CHANGED
from openedx.features.name_affirmation_api.utils import is_name_affirmation_installed

Expand Down
2 changes: 1 addition & 1 deletion common/djangoapps/student/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
UserCelebration,
UserProfile
)
from common.djangoapps.student.models_api import confirm_name_change, do_name_change_request, get_name
from common.djangoapps.student.api import get_name, do_name_change_request, confirm_name_change
from common.djangoapps.student.tests.factories import AccountRecoveryFactory, CourseEnrollmentFactory, UserFactory
from lms.djangoapps.courseware.models import DynamicUpgradeDeadlineConfiguration
from lms.djangoapps.courseware.toggles import (
Expand Down
Loading
Loading