MST-157 PART-2 Complete the functionality of searching for user info on program enrollment. The search result will be displayed on support tool's frontend.
This commit is contained in:
@@ -26,8 +26,9 @@ from .reading import (
|
||||
get_program_enrollment,
|
||||
get_provider_slug,
|
||||
get_saml_provider_for_organization,
|
||||
get_saml_provider_for_program,
|
||||
get_users_by_external_keys
|
||||
get_org_key_for_program,
|
||||
get_users_by_external_keys,
|
||||
get_users_by_external_keys_and_org_key
|
||||
)
|
||||
from .writing import (
|
||||
change_program_course_enrollment_status,
|
||||
|
||||
@@ -342,6 +342,44 @@ def _remove_none_values(dictionary):
|
||||
}
|
||||
|
||||
|
||||
def get_users_by_external_keys_and_org_key(external_user_keys, org_key):
|
||||
"""
|
||||
Given an organization_key and a set of external keys,
|
||||
return a dict from external user keys to Users.
|
||||
|
||||
Args:
|
||||
external_user_keys (sequence[str]):
|
||||
external user keys used by the program creator's IdP.
|
||||
org_key (str):
|
||||
The organization short name of which the external_user_key belongs to
|
||||
|
||||
Returns: dict[str: User|None]
|
||||
A dict mapping external user keys to Users.
|
||||
If an external user key is not registered, then None is returned instead
|
||||
of a User for that key.
|
||||
|
||||
Raises:
|
||||
BadOrganizationShortNameException
|
||||
ProviderDoesNotExistsException
|
||||
ProviderConfigurationException
|
||||
"""
|
||||
saml_provider = get_saml_provider_by_org_key(org_key)
|
||||
social_auth_uids = {
|
||||
saml_provider.get_social_auth_uid(external_user_key)
|
||||
for external_user_key in external_user_keys
|
||||
}
|
||||
social_auths = UserSocialAuth.objects.filter(uid__in=social_auth_uids)
|
||||
found_users_by_external_keys = {
|
||||
saml_provider.get_remote_id_from_social_auth(social_auth): social_auth.user
|
||||
for social_auth in social_auths
|
||||
}
|
||||
# Default all external keys to None, because external keys
|
||||
# without a User will not appear in `found_users_by_external_keys`.
|
||||
users_by_external_keys = {key: None for key in external_user_keys}
|
||||
users_by_external_keys.update(found_users_by_external_keys)
|
||||
return users_by_external_keys
|
||||
|
||||
|
||||
def get_users_by_external_keys(program_uuid, external_user_keys):
|
||||
"""
|
||||
Given a program and a set of external keys,
|
||||
@@ -365,21 +403,8 @@ def get_users_by_external_keys(program_uuid, external_user_keys):
|
||||
ProviderDoesNotExistsException
|
||||
ProviderConfigurationException
|
||||
"""
|
||||
saml_provider = get_saml_provider_for_program(program_uuid)
|
||||
social_auth_uids = {
|
||||
saml_provider.get_social_auth_uid(external_user_key)
|
||||
for external_user_key in external_user_keys
|
||||
}
|
||||
social_auths = UserSocialAuth.objects.filter(uid__in=social_auth_uids)
|
||||
found_users_by_external_keys = {
|
||||
saml_provider.get_remote_id_from_social_auth(social_auth): social_auth.user
|
||||
for social_auth in social_auths
|
||||
}
|
||||
# Default all external keys to None, because external keys
|
||||
# without a User will not appear in `found_users_by_external_keys`.
|
||||
users_by_external_keys = {key: None for key in external_user_keys}
|
||||
users_by_external_keys.update(found_users_by_external_keys)
|
||||
return users_by_external_keys
|
||||
org_key = get_org_key_for_program(program_uuid)
|
||||
return get_users_by_external_keys_and_org_key(external_user_keys, org_key)
|
||||
|
||||
|
||||
def get_external_key_by_user_and_course(user, course_key):
|
||||
@@ -409,20 +434,38 @@ def get_external_key_by_user_and_course(user, course_key):
|
||||
return relevant_pce.program_enrollment.external_user_key
|
||||
|
||||
|
||||
def get_saml_provider_for_program(program_uuid):
|
||||
def get_saml_provider_by_org_key(org_key):
|
||||
"""
|
||||
Return currently configured SAML provider for the Organization
|
||||
Returns the SAML provider associated with the provided org_key
|
||||
|
||||
Arguments:
|
||||
org_key (str)
|
||||
|
||||
Returns: SAMLProvider
|
||||
|
||||
Raises:
|
||||
BadOrganizationShortNameException
|
||||
"""
|
||||
try:
|
||||
organization = Organization.objects.get(short_name=org_key)
|
||||
except Organization.DoesNotExist:
|
||||
raise BadOrganizationShortNameException(org_key)
|
||||
return get_saml_provider_for_organization(organization)
|
||||
|
||||
|
||||
def get_org_key_for_program(program_uuid):
|
||||
"""
|
||||
Return the key of the first Organization
|
||||
administering the given program.
|
||||
|
||||
Arguments:
|
||||
program_uuid (UUID|str)
|
||||
|
||||
Returns: SAMLProvider
|
||||
Returns: org_key (str)
|
||||
|
||||
Raises:
|
||||
ProgramDoesNotExistException
|
||||
ProgramHasNoAuthoringOrganizationException
|
||||
BadOrganizationShortNameException
|
||||
"""
|
||||
program = get_programs(uuid=program_uuid)
|
||||
if program is None:
|
||||
@@ -431,11 +474,7 @@ def get_saml_provider_for_program(program_uuid):
|
||||
org_key = authoring_orgs[0].get('key') if authoring_orgs else None
|
||||
if not org_key:
|
||||
raise ProgramHasNoAuthoringOrganizationException(program_uuid)
|
||||
try:
|
||||
organization = Organization.objects.get(short_name=org_key)
|
||||
except Organization.DoesNotExist:
|
||||
raise BadOrganizationShortNameException(org_key)
|
||||
return get_saml_provider_for_organization(organization)
|
||||
return org_key
|
||||
|
||||
|
||||
def get_saml_provider_for_organization(organization):
|
||||
|
||||
@@ -5,7 +5,14 @@ Serializers for use in the support app.
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from student.models import ManualEnrollmentAudit
|
||||
from student.models import CourseEnrollment, ManualEnrollmentAudit
|
||||
from lms.djangoapps.program_enrollments.models import (
|
||||
ProgramEnrollment,
|
||||
ProgramCourseEnrollment,
|
||||
)
|
||||
|
||||
DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S'
|
||||
# pylint: disable=abstract-method
|
||||
|
||||
|
||||
class ManualEnrollmentSerializer(serializers.ModelSerializer):
|
||||
@@ -15,3 +22,57 @@ class ManualEnrollmentSerializer(serializers.ModelSerializer):
|
||||
class Meta(object):
|
||||
model = ManualEnrollmentAudit
|
||||
fields = ('enrolled_by', 'time_stamp', 'reason')
|
||||
|
||||
|
||||
class CourseEnrollmentSerializer(serializers.Serializer):
|
||||
""" Serializers a student_courseenrollment model object """
|
||||
course_id = serializers.CharField()
|
||||
is_active = serializers.BooleanField()
|
||||
mode = serializers.CharField()
|
||||
|
||||
class Meta(object):
|
||||
model = CourseEnrollment
|
||||
|
||||
|
||||
class ProgramCourseEnrollmentSerializer(serializers.Serializer):
|
||||
""" Serializes a Program Course Enrollment model object """
|
||||
created = serializers.DateTimeField(format=DATETIME_FORMAT)
|
||||
modified = serializers.DateTimeField(format=DATETIME_FORMAT)
|
||||
status = serializers.CharField()
|
||||
course_key = serializers.CharField()
|
||||
course_enrollment = CourseEnrollmentSerializer()
|
||||
|
||||
class Meta(object):
|
||||
model = ProgramCourseEnrollment
|
||||
|
||||
|
||||
class ProgramEnrollmentSerializer(serializers.Serializer):
|
||||
""" Serializes a Program Enrollment Model object """
|
||||
created = serializers.DateTimeField(format=DATETIME_FORMAT)
|
||||
modified = serializers.DateTimeField(format=DATETIME_FORMAT)
|
||||
external_user_key = serializers.CharField()
|
||||
status = serializers.CharField()
|
||||
program_uuid = serializers.UUIDField()
|
||||
program_course_enrollments = ProgramCourseEnrollmentSerializer(many=True)
|
||||
|
||||
class Meta(object):
|
||||
model = ProgramEnrollment
|
||||
|
||||
|
||||
def serialize_user_info(user, user_social_auth=None):
|
||||
"""
|
||||
Helper method to serialize resulting in user_info_object
|
||||
based on passed in django models
|
||||
"""
|
||||
user_info = {
|
||||
'username': user.username,
|
||||
'email': user.email,
|
||||
}
|
||||
if user_social_auth:
|
||||
_, external_key = user_social_auth.uid.split(':', 1)
|
||||
user_info['external_user_key'] = external_key
|
||||
user_info['sso'] = {
|
||||
'uid': user_social_auth.uid,
|
||||
'provider': user_social_auth.provider
|
||||
}
|
||||
return user_info
|
||||
|
||||
@@ -4,17 +4,14 @@ import { Button, InputText, StatusAlert, InputSelect } from '@edx/paragon';
|
||||
|
||||
export const ProgramEnrollmentsInspectorPage = props => (
|
||||
<form method="get">
|
||||
{props.successes.length > 0 && (
|
||||
{props.errors.map(errorItem => (
|
||||
<StatusAlert
|
||||
open
|
||||
alertType="success"
|
||||
dialog={(
|
||||
<div>
|
||||
<span></span>
|
||||
</div>
|
||||
)}
|
||||
dismissible={false}
|
||||
alertType="danger"
|
||||
dialog={errorItem}
|
||||
/>
|
||||
)}
|
||||
))}
|
||||
<div key="edX_accounts">
|
||||
<InputText
|
||||
name="edx_user"
|
||||
@@ -43,15 +40,21 @@ export const ProgramEnrollmentsInspectorPage = props => (
|
||||
);
|
||||
|
||||
ProgramEnrollmentsInspectorPage.propTypes = {
|
||||
successes: PropTypes.arrayOf(PropTypes.string),
|
||||
errors: PropTypes.arrayOf(PropTypes.string),
|
||||
learnerInfo: PropTypes.string,
|
||||
learnerInfo: PropTypes.shape({
|
||||
user: PropTypes.shape({
|
||||
external_user_key: PropTypes.string,
|
||||
username: PropTypes.string,
|
||||
}),
|
||||
enrollments: PropTypes.arrayOf(
|
||||
PropTypes.string,
|
||||
),
|
||||
}),
|
||||
orgKeys: PropTypes.arrayOf(PropTypes.object),
|
||||
};
|
||||
|
||||
ProgramEnrollmentsInspectorPage.defaultProps = {
|
||||
successes: [],
|
||||
errors: [],
|
||||
learnerInfo: '',
|
||||
learnerInfo: {},
|
||||
orgKeys: [],
|
||||
};
|
||||
|
||||
@@ -25,7 +25,10 @@ from common.test.utils import disable_signal
|
||||
from course_modes.models import CourseMode
|
||||
from course_modes.tests.factories import CourseModeFactory
|
||||
from lms.djangoapps.program_enrollments.tests.factories import ProgramCourseEnrollmentFactory, ProgramEnrollmentFactory
|
||||
from lms.djangoapps.support.serializers import ProgramEnrollmentSerializer
|
||||
from lms.djangoapps.verify_student.models import VerificationDeadline
|
||||
from lms.djangoapps.verify_student.services import IDVerificationService
|
||||
from lms.djangoapps.verify_student.tests.factories import SSOVerificationFactory
|
||||
from student.models import ENROLLED_TO_ENROLLED, CourseEnrollment, CourseEnrollmentAttribute, ManualEnrollmentAudit
|
||||
from student.roles import GlobalStaff, SupportStaffRole
|
||||
from student.tests.factories import CourseEnrollmentFactory, UserFactory
|
||||
@@ -545,6 +548,7 @@ class SupportViewLinkProgramEnrollmentsTests(SupportViewTestCase):
|
||||
assert render_call_dict['errors'] == [msg]
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ProgramEnrollmentsInspectorViewTests(SupportViewTestCase):
|
||||
"""
|
||||
View tests for Program Enrollments Inspector
|
||||
@@ -603,10 +607,10 @@ class ProgramEnrollmentsInspectorViewTests(SupportViewTestCase):
|
||||
user_social_auth = UserSocialAuth.objects.create(
|
||||
user=user,
|
||||
uid='{0}:{1}'.format(org_key, external_user_key),
|
||||
provider=org_key
|
||||
provider='tpa-saml'
|
||||
)
|
||||
user_info['external_user_key'] = external_user_key
|
||||
user_info['SSO'] = {
|
||||
user_info['sso'] = {
|
||||
'uid': user_social_auth.uid,
|
||||
'provider': user_social_auth.provider
|
||||
}
|
||||
@@ -618,27 +622,14 @@ class ProgramEnrollmentsInspectorViewTests(SupportViewTestCase):
|
||||
If the edx user is provided, it will try to SSO the user with the enrollments
|
||||
Return the expected info object that should be created based on the model setup
|
||||
"""
|
||||
expected_enrollments = []
|
||||
program_enrollments = []
|
||||
for program_uuid in program_uuids:
|
||||
expected_enrollment = {}
|
||||
expected_course_enrollment = {}
|
||||
course_enrollment = None
|
||||
program_enrollment = ProgramEnrollmentFactory.create(
|
||||
external_user_key=external_user_key,
|
||||
program_uuid=program_uuid,
|
||||
user=edx_user
|
||||
)
|
||||
expected_enrollment['program_enrollment'] = {
|
||||
'created': self._serialize_datetime(
|
||||
program_enrollment.created
|
||||
),
|
||||
'modified': self._serialize_datetime(
|
||||
program_enrollment.modified
|
||||
),
|
||||
'program_uuid': program_enrollment.program_uuid,
|
||||
'external_user_key': external_user_key,
|
||||
'status': program_enrollment.status
|
||||
}
|
||||
|
||||
for course_id in course_ids:
|
||||
if edx_user:
|
||||
@@ -648,11 +639,6 @@ class ProgramEnrollmentsInspectorViewTests(SupportViewTestCase):
|
||||
mode=CourseMode.MASTERS,
|
||||
is_active=True
|
||||
)
|
||||
expected_course_enrollment = {
|
||||
'course_id': str(course_enrollment.course_id),
|
||||
'is_active': course_enrollment.is_active,
|
||||
'mode': course_enrollment.mode,
|
||||
}
|
||||
|
||||
program_course_enrollment = ProgramCourseEnrollmentFactory.create(
|
||||
program_enrollment=program_enrollment,
|
||||
@@ -660,26 +646,22 @@ class ProgramEnrollmentsInspectorViewTests(SupportViewTestCase):
|
||||
course_enrollment=course_enrollment,
|
||||
status='active',
|
||||
)
|
||||
expected_program_course_enrollment = {
|
||||
'created': self._serialize_datetime(
|
||||
program_course_enrollment.created
|
||||
),
|
||||
'modified': self._serialize_datetime(
|
||||
program_course_enrollment.modified
|
||||
),
|
||||
'status': program_course_enrollment.status,
|
||||
'course_key': str(program_course_enrollment.course_key),
|
||||
}
|
||||
if expected_course_enrollment:
|
||||
expected_program_course_enrollment['course_enrollment'] = expected_course_enrollment
|
||||
|
||||
expected_enrollment.setdefault('program_course_enrollments', []).append(
|
||||
expected_program_course_enrollment
|
||||
)
|
||||
program_enrollments.append(program_enrollment)
|
||||
|
||||
expected_enrollments.append(expected_enrollment)
|
||||
serialized = ProgramEnrollmentSerializer(program_enrollments, many=True)
|
||||
return serialized.data
|
||||
|
||||
return expected_enrollments
|
||||
def _construct_id_verification(self, user):
|
||||
"""
|
||||
Helper function to create the SSO verified record for the user
|
||||
so that the user is ID Verified
|
||||
"""
|
||||
SSOVerificationFactory(
|
||||
identity_provider_slug=self.org_key_list[0],
|
||||
user=user,
|
||||
)
|
||||
return IDVerificationService.user_status(user)
|
||||
|
||||
@patch_render
|
||||
def test_search_username_well_connected_user(self, mocked_render):
|
||||
@@ -688,6 +670,7 @@ class ProgramEnrollmentsInspectorViewTests(SupportViewTestCase):
|
||||
self.org_key_list[0],
|
||||
self.external_user_key
|
||||
)
|
||||
id_verified = self._construct_id_verification(created_user)
|
||||
expected_enrollments = self._construct_enrollments(
|
||||
[self.program_uuid],
|
||||
[self.course.id],
|
||||
@@ -699,7 +682,8 @@ class ProgramEnrollmentsInspectorViewTests(SupportViewTestCase):
|
||||
})
|
||||
expected_info = {
|
||||
'user': expected_user_info,
|
||||
'enrollments': expected_enrollments
|
||||
'enrollments': expected_enrollments,
|
||||
'id_verification': id_verified
|
||||
}
|
||||
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
@@ -712,7 +696,8 @@ class ProgramEnrollmentsInspectorViewTests(SupportViewTestCase):
|
||||
'edx_user': created_user.email
|
||||
})
|
||||
expected_info = {
|
||||
'user': expected_user_info
|
||||
'user': expected_user_info,
|
||||
'id_verification': IDVerificationService.user_status(created_user)
|
||||
}
|
||||
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
@@ -729,7 +714,8 @@ class ProgramEnrollmentsInspectorViewTests(SupportViewTestCase):
|
||||
'edx_user': created_user.email
|
||||
})
|
||||
expected_info = {
|
||||
'user': expected_user_info
|
||||
'user': expected_user_info,
|
||||
'id_verification': IDVerificationService.user_status(created_user),
|
||||
}
|
||||
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
@@ -753,7 +739,8 @@ class ProgramEnrollmentsInspectorViewTests(SupportViewTestCase):
|
||||
})
|
||||
expected_info = {
|
||||
'user': expected_user_info,
|
||||
'enrollments': expected_enrollments
|
||||
'enrollments': expected_enrollments,
|
||||
'id_verification': IDVerificationService.user_status(created_user),
|
||||
}
|
||||
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
@@ -774,7 +761,110 @@ class ProgramEnrollmentsInspectorViewTests(SupportViewTestCase):
|
||||
})
|
||||
expected_info = {
|
||||
'user': expected_user_info,
|
||||
'id_verification': IDVerificationService.user_status(created_user),
|
||||
}
|
||||
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
assert expected_info == render_call_dict['learner_program_enrollments']
|
||||
|
||||
@patch_render
|
||||
def test_search_username_user_id_verified(self, mocked_render):
|
||||
created_user, expected_user_info = self._construct_user(
|
||||
'user_not_connected'
|
||||
)
|
||||
id_verified = self._construct_id_verification(created_user)
|
||||
expected_info = {
|
||||
'user': expected_user_info,
|
||||
'id_verification': id_verified
|
||||
}
|
||||
|
||||
self.client.get(self.url, data={
|
||||
'edx_user': created_user.email
|
||||
})
|
||||
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
assert expected_info == render_call_dict['learner_program_enrollments']
|
||||
|
||||
@patch_render
|
||||
def test_search_external_key_well_connected(self, mocked_render):
|
||||
created_user, expected_user_info = self._construct_user(
|
||||
'test_user_connected',
|
||||
self.org_key_list[0],
|
||||
self.external_user_key
|
||||
)
|
||||
expected_enrollments = self._construct_enrollments(
|
||||
[self.program_uuid],
|
||||
[self.course.id],
|
||||
self.external_user_key,
|
||||
created_user
|
||||
)
|
||||
id_verified = self._construct_id_verification(created_user)
|
||||
self.client.get(self.url, data={
|
||||
'external_user_key': self.external_user_key,
|
||||
'IdPSelect': self.org_key_list[0]
|
||||
})
|
||||
expected_info = {
|
||||
'user': expected_user_info,
|
||||
'enrollments': expected_enrollments,
|
||||
'id_verification': id_verified,
|
||||
}
|
||||
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
assert expected_info == render_call_dict['learner_program_enrollments']
|
||||
|
||||
@ddt.data(
|
||||
('aabbcc', ''),
|
||||
('', 'test_org')
|
||||
)
|
||||
@ddt.unpack
|
||||
@patch_render
|
||||
def test_search_external_key_no_idp(self, user_key_input, idp_input, mocked_render):
|
||||
self.client.get(self.url, data={
|
||||
'external_user_key': user_key_input,
|
||||
'IdPSelect': idp_input,
|
||||
})
|
||||
|
||||
expected_errors = [
|
||||
"To perform a search, you must provide either the student's "
|
||||
"(a) edX username, "
|
||||
"(b) email address associated with their edX account, or "
|
||||
"(c) Identity-providing institution and external key!"
|
||||
]
|
||||
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
assert {} == render_call_dict['learner_program_enrollments']
|
||||
assert expected_errors == render_call_dict['errors']
|
||||
|
||||
@patch_render
|
||||
def test_search_external_user_not_connected(self, mocked_render):
|
||||
expected_enrollments = self._construct_enrollments(
|
||||
[self.program_uuid],
|
||||
[self.course.id],
|
||||
self.external_user_key,
|
||||
)
|
||||
self.client.get(self.url, data={
|
||||
'external_user_key': self.external_user_key,
|
||||
'IdPSelect': self.org_key_list[0]
|
||||
})
|
||||
expected_info = {
|
||||
'enrollments': expected_enrollments
|
||||
}
|
||||
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
assert expected_info == render_call_dict['learner_program_enrollments']
|
||||
|
||||
@patch_render
|
||||
def test_search_external_user_not_in_system(self, mocked_render):
|
||||
external_user_key = 'not_in_system'
|
||||
self.client.get(self.url, data={
|
||||
'external_user_key': external_user_key,
|
||||
'IdPSelect': self.org_key_list[0],
|
||||
})
|
||||
|
||||
expected_errors = [
|
||||
'No user found for external key {} for institution {}'.format(
|
||||
external_user_key, self.org_key_list[0]
|
||||
)
|
||||
]
|
||||
render_call_dict = mocked_render.call_args[0][1]
|
||||
assert expected_errors == render_call_dict['errors']
|
||||
|
||||
@@ -15,9 +15,20 @@ from social_django.models import UserSocialAuth
|
||||
from edxmako.shortcuts import render_to_response
|
||||
from lms.djangoapps.program_enrollments.api import (
|
||||
fetch_program_enrollments_by_student,
|
||||
get_users_by_external_keys_and_org_key,
|
||||
link_program_enrollments
|
||||
)
|
||||
from lms.djangoapps.program_enrollments.exceptions import (
|
||||
BadOrganizationShortNameException,
|
||||
ProviderConfigurationException,
|
||||
ProviderDoesNotExistException
|
||||
)
|
||||
from lms.djangoapps.support.decorators import require_support_permission
|
||||
from lms.djangoapps.support.serializers import (
|
||||
ProgramEnrollmentSerializer,
|
||||
serialize_user_info
|
||||
)
|
||||
from lms.djangoapps.verify_student.services import IDVerificationService
|
||||
from third_party_auth.models import SAMLProviderConfig
|
||||
|
||||
TEMPLATE_PATH = 'support/link_program_enrollments.html'
|
||||
@@ -133,17 +144,27 @@ class ProgramEnrollmentsInspectorView(View):
|
||||
if error:
|
||||
errors.append(error)
|
||||
elif org_key and external_user_key:
|
||||
learner_program_enrollments = {}
|
||||
elif not external_user_key and org_key:
|
||||
learner_program_enrollments = self._get_external_user_info(
|
||||
external_user_key,
|
||||
org_key
|
||||
)
|
||||
if not learner_program_enrollments:
|
||||
errors.append(
|
||||
'No user found for external key {} for institution {}'.format(
|
||||
external_user_key, org_key
|
||||
)
|
||||
)
|
||||
else:
|
||||
errors.append(
|
||||
'You must provide either the edX username or email, or the '
|
||||
'Learner Account Provider and External Key pair to do search!'
|
||||
"To perform a search, you must provide either the student's "
|
||||
"(a) edX username, "
|
||||
"(b) email address associated with their edX account, or "
|
||||
"(c) Identity-providing institution and external key!"
|
||||
)
|
||||
|
||||
return render_to_response(
|
||||
self.CONSOLE_TEMPLATE_PATH,
|
||||
{
|
||||
'successes': [],
|
||||
'errors': errors,
|
||||
'learner_program_enrollments': learner_program_enrollments,
|
||||
'org_keys': self._get_org_keys_with_idp(),
|
||||
@@ -168,32 +189,59 @@ class ProgramEnrollmentsInspectorView(View):
|
||||
and program_enrollments_info. If we cannot identify the user, return
|
||||
empty object and error.
|
||||
"""
|
||||
user_info = {}
|
||||
external_key = None
|
||||
try:
|
||||
user = User.objects.get(Q(username=username_or_email) | Q(email=username_or_email))
|
||||
user_info['username'] = user.username
|
||||
user_info['email'] = user.email
|
||||
user_social_auth = None
|
||||
try:
|
||||
user_social_auth = UserSocialAuth.objects.get(user=user)
|
||||
_, external_key = user_social_auth.uid.split(':', 1)
|
||||
user_info['external_user_key'] = external_key
|
||||
user_info['SSO'] = {
|
||||
'uid': user_social_auth.uid,
|
||||
'provider': user_social_auth.provider
|
||||
}
|
||||
except UserSocialAuth.DoesNotExist:
|
||||
pass
|
||||
|
||||
user_info = serialize_user_info(user, user_social_auth)
|
||||
enrollments = self._get_enrollments(user=user)
|
||||
result = {'user': user_info}
|
||||
if enrollments:
|
||||
result['enrollments'] = enrollments
|
||||
|
||||
result['id_verification'] = IDVerificationService.user_status(user)
|
||||
return result, ''
|
||||
except User.DoesNotExist:
|
||||
return {}, 'Could not find edx account with {}'.format(username_or_email)
|
||||
|
||||
def _get_external_user_info(self, external_user_key, org_key):
|
||||
"""
|
||||
Provided the external_user_key and org_key, return edx account info
|
||||
and program_enrollments_info if any. If we cannot identify the data,
|
||||
return empty object.
|
||||
"""
|
||||
found_user = None
|
||||
result = {}
|
||||
try:
|
||||
users_by_key = get_users_by_external_keys_and_org_key(
|
||||
[external_user_key],
|
||||
org_key
|
||||
)
|
||||
found_user = users_by_key.get(external_user_key)
|
||||
except (
|
||||
BadOrganizationShortNameException,
|
||||
ProviderConfigurationException,
|
||||
ProviderDoesNotExistException
|
||||
):
|
||||
# We cannot identify edX user from external_user_key and org_key pair
|
||||
pass
|
||||
|
||||
if found_user:
|
||||
try:
|
||||
user_social_auth = UserSocialAuth.objects.get(user=found_user)
|
||||
except UserSocialAuth.DoesNotExist:
|
||||
user_social_auth = None
|
||||
user_info = serialize_user_info(found_user, user_social_auth)
|
||||
result['user'] = user_info
|
||||
result['id_verification'] = IDVerificationService.user_status(found_user)
|
||||
enrollments = self._get_enrollments(external_user_key=external_user_key)
|
||||
if enrollments:
|
||||
result['enrollments'] = enrollments
|
||||
return result
|
||||
|
||||
def _get_enrollments(self, user=None, external_user_key=None):
|
||||
"""
|
||||
With the user or external_user_key passed in,
|
||||
@@ -204,55 +252,5 @@ class ProgramEnrollmentsInspectorView(View):
|
||||
user=user,
|
||||
external_user_key=external_user_key
|
||||
).prefetch_related('program_course_enrollments')
|
||||
|
||||
enrollments_by_program_uuid = {}
|
||||
for program_enrollment in program_enrollments:
|
||||
serialized_program_enrollment = self._serialize_program_enrollment(program_enrollment)
|
||||
enrollment_item = {
|
||||
'program_enrollment': serialized_program_enrollment
|
||||
}
|
||||
program_course_enrollments = program_enrollment.program_course_enrollments.all()
|
||||
for program_course_enrollment in program_course_enrollments.select_related(
|
||||
'course_enrollment'
|
||||
):
|
||||
serialized_program_course_enrollment = self._serialize_program_course_enrollment(
|
||||
program_course_enrollment
|
||||
)
|
||||
enrollment_item.setdefault('program_course_enrollments', []).append(
|
||||
serialized_program_course_enrollment
|
||||
)
|
||||
enrollments_by_program_uuid[program_enrollment.program_uuid] = enrollment_item
|
||||
|
||||
return list(enrollments_by_program_uuid.values())
|
||||
|
||||
def _serialize_program_enrollment(self, program_enrollment):
|
||||
if not program_enrollment:
|
||||
return {}
|
||||
|
||||
return {
|
||||
'created': program_enrollment.created.strftime(DATETIME_FORMAT),
|
||||
'modified': program_enrollment.modified.strftime(DATETIME_FORMAT),
|
||||
'program_uuid': str(program_enrollment.program_uuid),
|
||||
'external_user_key': program_enrollment.external_user_key,
|
||||
'status': program_enrollment.status
|
||||
}
|
||||
|
||||
def _serialize_program_course_enrollment(self, program_course_enrollment):
|
||||
"""
|
||||
Return a dictionary of ProgramCourseEnrollment serialized
|
||||
"""
|
||||
if not program_course_enrollment:
|
||||
return {}
|
||||
|
||||
course_enrollment = program_course_enrollment.course_enrollment
|
||||
return {
|
||||
'created': program_course_enrollment.created.strftime(DATETIME_FORMAT),
|
||||
'modified': program_course_enrollment.modified.strftime(DATETIME_FORMAT),
|
||||
'course_enrollment': {
|
||||
'course_id': str(course_enrollment.course_id),
|
||||
'is_active': course_enrollment.is_active,
|
||||
'mode': course_enrollment.mode,
|
||||
},
|
||||
'status': program_course_enrollment.status,
|
||||
'course_key': str(program_course_enrollment.course_key),
|
||||
}
|
||||
serialized = ProgramEnrollmentSerializer(program_enrollments, many=True)
|
||||
return serialized.data
|
||||
|
||||
@@ -26,7 +26,6 @@ from openedx.core.djangolib.js_utils import js_escaped_string
|
||||
component="ProgramEnrollmentsInspectorPage",
|
||||
id="entitlement-support-page",
|
||||
props={
|
||||
'successes': successes,
|
||||
'errors': errors,
|
||||
'learnerInfo': learner_program_enrollments,
|
||||
'orgKeys': org_keys
|
||||
|
||||
Reference in New Issue
Block a user