diff --git a/lms/djangoapps/program_enrollments/api/reading.py b/lms/djangoapps/program_enrollments/api/reading.py index 10e1c2f6035ff24b4299c8d16336a632c4784305..47ee586201062461684b16af8e4526ef7f3ef8c4 100644 --- a/lms/djangoapps/program_enrollments/api/reading.py +++ b/lms/djangoapps/program_enrollments/api/reading.py @@ -5,7 +5,10 @@ Outside of this subpackage, import these functions from `lms.djangoapps.program_enrollments.api`. """ +from functools import reduce +from operator import or_ +from django.db.models import Q from organizations.models import Organization from social_django.models import UserSocialAuth @@ -257,7 +260,7 @@ def fetch_program_enrollments_by_student( ) filters = { "user": user, - "external_user_key": external_user_key, + "external_user_key__iexact": external_user_key, "program_uuid__in": program_uuids, "curriculum_uuid__in": curriculum_uuids, "status__in": program_enrollment_statuses, @@ -412,11 +415,14 @@ def get_users_by_external_keys_and_org_key(external_user_keys, org_key): 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.update({ - saml_provider.get_remote_id_from_social_auth(social_auth): social_auth.user - for social_auth in social_auths - }) + if social_auth_uids: + # Filter should be case insensitive + query_filter = reduce(or_, [Q(uid__iexact=uid) for uid in social_auth_uids]) + social_auths = UserSocialAuth.objects.filter(query_filter) + found_users_by_external_keys.update({ + 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`. diff --git a/lms/djangoapps/support/tests/test_views.py b/lms/djangoapps/support/tests/test_views.py index 55de44454407e6abc21ab8e3776c64f38ee36fd6..5dfe8669d42c8a5e1f9ce6764dbac33aedc81b6d 100644 --- a/lms/djangoapps/support/tests/test_views.py +++ b/lms/djangoapps/support/tests/test_views.py @@ -1069,6 +1069,38 @@ class ProgramEnrollmentsInspectorViewTests(SupportViewTestCase): render_call_dict = mocked_render.call_args[0][1] assert expected_error == render_call_dict['error'] + @patch_render + def test_search_external_user_case_insensitive(self, mocked_render): + external_user_key = 'AbCdEf123' + requested_external_user_key = 'aBcDeF123' + + created_user, expected_user_info = self._construct_user( + 'test_user_connected', + self.org_key_list[0], + external_user_key + ) + + expected_enrollments = self._construct_enrollments( + [self.program_uuid], + [self.course.id], + external_user_key, + created_user + ) + id_verified = self._construct_id_verification(created_user) + + self.client.get(self.url, data={ + 'external_user_key': requested_external_user_key, + 'org_key': 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'] + class SsoRecordsTests(SupportViewTestCase): # lint-amnesty, pylint: disable=missing-class-docstring diff --git a/lms/djangoapps/support/views/program_enrollments.py b/lms/djangoapps/support/views/program_enrollments.py index fa42fa32bece4c387fd379343150f7ad5beca6cf..22435559b71854fc4bf02dee1d8133d0238c3e03 100644 --- a/lms/djangoapps/support/views/program_enrollments.py +++ b/lms/djangoapps/support/views/program_enrollments.py @@ -224,7 +224,9 @@ class ProgramEnrollmentsInspectorView(View): [external_user_key], org_key ) - found_user = users_by_key.get(external_user_key) + # Remove entries with no corresponding user and convert keys to lowercase + users_by_key_lower = {key.lower(): value for key, value in users_by_key.items() if value} + found_user = users_by_key_lower.get(external_user_key.lower()) except ( BadOrganizationShortNameException, ProviderDoesNotExistException