diff --git a/openedx/core/djangoapps/appsembler/api/tests/test_user_api.py b/openedx/core/djangoapps/appsembler/api/tests/test_user_api.py index cf50d520608c..e23d05c7c160 100644 --- a/openedx/core/djangoapps/appsembler/api/tests/test_user_api.py +++ b/openedx/core/djangoapps/appsembler/api/tests/test_user_api.py @@ -32,6 +32,11 @@ @mock.patch(APPSEMBLER_API_VIEWS_MODULE + '.UserIndexViewSet.throttle_classes', []) class UserIndexViewSetTest(TestCase): + # Fixtures to be used for filtering + JANE_DUE_USERNAME = 'jane.due' + JANE_DUE_EMAIL = '{username}@user.api.example.com'.format(username=JANE_DUE_USERNAME) + NON_USER_EMAIL = 'not.for.a.user@user.api.example.com' + def setUp(self): """ Set up test data for site isolation @@ -51,7 +56,12 @@ def setUp(self): self.my_site_org = OrganizationFactory(sites=[self.my_site]) # Set up users and enrollments for 'my site' - self.my_site_users = [UserFactory() for i in range(3)] + self.my_site_users = [ + UserFactory.create(email=self.JANE_DUE_EMAIL, username=self.JANE_DUE_USERNAME), + UserFactory.create(), + UserFactory.create(), + ] + for user in self.my_site_users: UserOrganizationMappingFactory(user=user, organization=self.my_site_org) @@ -90,6 +100,32 @@ def test_get_all_users_for_site(self): user_ids = [rec['id'] for rec in results] assert set(user_ids) == set([obj.id for obj in expected_users]) + @ddt.unpack + @ddt.data( + {'email': JANE_DUE_EMAIL.lower(), 'expected_count': 1, 'msg': 'Should find Jane (lower case) in the users'}, + {'email': JANE_DUE_EMAIL.upper(), 'expected_count': 1, 'msg': 'Should find Jane (upper case) in the users'}, + {'email': JANE_DUE_USERNAME, 'expected_count': 0, 'msg': 'Should not do partial matching'}, + {'email': NON_USER_EMAIL, 'expected_count': 0, 'msg': 'Should not match any user.'}, + ) + def test_filter_by_email(self, email, expected_count, msg): + """ + Test the email filters matching. + """ + url = reverse('tahoe-api:v1:users-list') + request = APIRequestFactory().get(url, {'email_exact': email}) + request.META['HTTP_HOST'] = self.my_site.domain + force_authenticate(request, user=self.caller) + + view = resolve(url).func + response = view(request) + response.render() + results = response.data['results'] + + assert len(results) == expected_count, msg + if expected_count: + # Ignore the email case + assert results[0]['email'].lower() == email.lower(), msg + @skip("Need to implement user filter") def test_get_all_enrolled_learners_for_site(self): diff --git a/openedx/core/djangoapps/appsembler/api/v1/filters.py b/openedx/core/djangoapps/appsembler/api/v1/filters.py index e68621905d9d..904d62e86fa5 100644 --- a/openedx/core/djangoapps/appsembler/api/v1/filters.py +++ b/openedx/core/djangoapps/appsembler/api/v1/filters.py @@ -1,5 +1,6 @@ import django_filters +from django.contrib.auth import get_user_model from opaque_keys.edx.keys import CourseKey from openedx.core.djangoapps.content.course_overviews.models import ( CourseOverview, @@ -68,3 +69,15 @@ def filter_course_id(self, queryset, name, value): class Meta: model = CourseEnrollment fields = ['course_id', 'user_id', 'username', 'is_active', ] + + +class UserIndexFilter(django_filters.FilterSet): + '''Provides filtering for the User model objects in the UserIndexViewSet. + + ''' + + email_exact = django_filters.CharFilter(name='email', lookup_expr='iexact') + + class Meta: + model = get_user_model() + fields = ['email_exact'] diff --git a/openedx/core/djangoapps/appsembler/api/v1/views.py b/openedx/core/djangoapps/appsembler/api/v1/views.py index a74f29c6f17c..e399de1109d6 100644 --- a/openedx/core/djangoapps/appsembler/api/v1/views.py +++ b/openedx/core/djangoapps/appsembler/api/v1/views.py @@ -50,7 +50,8 @@ from openedx.core.djangoapps.appsembler.api.v1.api import enroll_learners_in_course from openedx.core.djangoapps.appsembler.api.v1.filters import ( CourseEnrollmentFilter, - CourseOverviewFilter + CourseOverviewFilter, + UserIndexFilter, ) from openedx.core.djangoapps.appsembler.api.v1.pagination import ( TahoeLimitOffsetPagination @@ -397,6 +398,7 @@ class UserIndexViewSet(TahoeAuthMixin, viewsets.ReadOnlyModelViewSet): serializer_class = UserIndexSerializer throttle_classes = (TahoeAPIUserThrottle,) filter_backends = (DjangoFilterBackend, ) + filter_class = UserIndexFilter def get_queryset(self): site = django.contrib.sites.shortcuts.get_current_site(self.request)