diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 0e00bcd15..08b22c0f4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -17,6 +17,10 @@ Unreleased ---------- * nothing unreleased +[4.32.1] +-------- +* feat: filter and sort learner by name/email + [4.32.0] -------- * feat: create DefaultEnterpriseEnrollmentRealization objects in bulk enrollment API, when applicable. diff --git a/enterprise/__init__.py b/enterprise/__init__.py index e4db7f1e3..aceba5514 100644 --- a/enterprise/__init__.py +++ b/enterprise/__init__.py @@ -2,4 +2,4 @@ Your project description goes here. """ -__version__ = "4.32.0" +__version__ = "4.32.1" diff --git a/enterprise/api/filters.py b/enterprise/api/filters.py index 92c1bb455..d29640207 100644 --- a/enterprise/api/filters.py +++ b/enterprise/api/filters.py @@ -6,6 +6,7 @@ from rest_framework.exceptions import ValidationError from django.contrib import auth +from django.db.models import Q from enterprise.models import EnterpriseCustomer, EnterpriseCustomerUser, SystemWideEnterpriseUserRoleAssignment @@ -100,6 +101,19 @@ def _filter_by_user_attributes(self, request, queryset): return queryset + def _filter_by_username_or_email(self, request, queryset): + """ + Filter queryset by email or username using the single 'username_or_email' query parameter + """ + username_or_email = request.query_params.get('username_or_email', None) + + if username_or_email: + users = User.objects.filter(Q(username__icontains=username_or_email) | Q(email=username_or_email)) \ + .values_list('id', flat=True) + return queryset.filter(user_id__in=users) + + return queryset + def _filter_by_enterprise_attributes(self, request, queryset): """ Filter queryset by enterprise_customer_uuid or enterprise role. @@ -133,7 +147,7 @@ def _filter_by_enterprise_attributes(self, request, queryset): def filter_queryset(self, request, queryset, view): """ - Apply incoming filters only if user is staff. If not, only filter by user's ID. + Apply incoming filters only if user is staff. If not, only filter by user's ID, email, or username. """ if request.user.is_staff: queryset = self._filter_by_user_attributes(request, queryset) @@ -142,6 +156,7 @@ def filter_queryset(self, request, queryset, view): else: queryset = queryset.filter(user_id=request.user.id) + queryset = self._filter_by_username_or_email(request, queryset) return queryset diff --git a/enterprise/api/v1/views/enterprise_customer_user.py b/enterprise/api/v1/views/enterprise_customer_user.py index 296f9fd63..198fa2787 100644 --- a/enterprise/api/v1/views/enterprise_customer_user.py +++ b/enterprise/api/v1/views/enterprise_customer_user.py @@ -1,14 +1,28 @@ """ Views for the ``enterprise-customer-user`` API endpoint. """ +from collections import OrderedDict + from django_filters.rest_framework import DjangoFilterBackend from rest_framework import filters +from rest_framework.response import Response from enterprise import models from enterprise.api.filters import EnterpriseCustomerUserFilterBackend from enterprise.api.pagination import PaginationWithFeatureFlags from enterprise.api.v1 import serializers from enterprise.api.v1.views.base_views import EnterpriseReadWriteModelViewSet +from enterprise.toggles import enterprise_features + + +def _single_page_pagination(results): + return OrderedDict([ + ('count', len(results)), + ('next', None), + ('previous', None), + ('results', results), + ('enterprise_features', enterprise_features()), + ]) class EnterpriseCustomerUserViewSet(EnterpriseReadWriteModelViewSet): @@ -24,7 +38,29 @@ class EnterpriseCustomerUserViewSet(EnterpriseReadWriteModelViewSet): 'enterprise_customer', 'user_id', 'active', ) filterset_fields = FIELDS - ordering_fields = FIELDS + ordering_fields = FIELDS + ('created',) + + def list(self, request, *args, **kwargs): + """ + Enterprise Customer User's Basic data list without pagination + + Besides what is laid out in filterset_fields and ordering_fields the following parameters are supported: + - username_or_email: filter by name or email substring in a single query parameter + - ordering=(-)username: Order by name + """ + queryset = self.get_queryset() + queryset = self.filter_queryset(queryset) + serializer = self.get_serializer(queryset, many=True) + # Manually sort by username + final_result = serializer.data + if ordering := request.query_params.get('ordering', None): + if 'username' in ordering: + def username_key(learner): + return learner['user']['username'] + is_descending = ordering[0] == '-' + final_result = sorted(final_result, key=username_key, reverse=is_descending) + paginated_result = _single_page_pagination(final_result) + return Response(paginated_result) def get_serializer_class(self): """