Skip to content

Commit

Permalink
fix: customer sorting error (#2226)
Browse files Browse the repository at this point in the history
* fix: customer sorting error

* fix: update test

* chore: update version
  • Loading branch information
katrinan029 authored Sep 4, 2024
1 parent f4b7b3d commit f8ea429
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 62 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ Unreleased
----------
* nothing unreleased

[4.24.0]
----------
* fix: customer sorting error in customer support tool endpoint and added user query param

[4.23.20]
----------
* feat: added migrations to remove client_id and client_secret from CanvasEnterpriseCustomerConfiguration
Expand Down
2 changes: 1 addition & 1 deletion enterprise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
Your project description goes here.
"""

__version__ = "4.23.20"
__version__ = "4.24.0"
128 changes: 67 additions & 61 deletions enterprise/api/v1/views/enterprise_customer_support.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

"""
Views for the ``enterprise-user`` API endpoint.
"""
Expand All @@ -25,18 +24,21 @@

class EnterpriseCustomerSupportPaginator(PageNumberPagination):
"""Custom paginator for the enterprise customer support."""

page_size = 8

def get_paginated_response(self, data):
"""Return a paginated style `Response` object for the given output data."""
return response.Response(
OrderedDict([
('count', self.page.paginator.count),
('num_pages', self.page.paginator.num_pages),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('results', data),
])
OrderedDict(
[
("count", self.page.paginator.count),
("num_pages", self.page.paginator.num_pages),
("next", self.get_next_link()),
("previous", self.get_previous_link()),
("results", data),
]
)
)

def paginate_queryset(self, queryset, request, view=None):
Expand All @@ -55,100 +57,100 @@ class EnterpriseCustomerSupportViewSet(EnterpriseReadOnlyModelViewSet):
"""
API views for the ``enterprise-customer-support`` API endpoint.
"""

queryset = models.PendingEnterpriseCustomerUser.objects.all()
filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
permission_classes = (permissions.IsAuthenticated,)
paginator = EnterpriseCustomerSupportPaginator()

ordering_fields = ['id']
filterset_fields = ['user_email']
ordering_fields = ["is_admin", "username", "pending_enterprise_customer"]

def filter_queryset_by_email(self, queryset, is_pending_user=False):
def filter_queryset_by_user_query(self, queryset, is_pending_user=False):
"""
Filter queryset based on user provided email address
Filter queryset based on user provided query
"""
filter_email = self.request.query_params.get('user_email', None)
user_query = self.request.query_params.get("user_query", None)

if filter_email:
if user_query:
if not is_pending_user:
queryset = queryset.filter(
user_id__in=User.objects.filter(Q(email__icontains=filter_email))
user_id__in=User.objects.filter(Q(email__icontains=user_query))
)
else:
queryset = queryset.filter(user_email=filter_email)
queryset = queryset.filter(user_email=user_query)

return queryset

def retrieve(self, request, *args, **kwargs):
"""
Filter down the queryset of groups available to the requesting uuid.
"""
enterprise_uuid = kwargs.get('enterprise_uuid', None)
enterprise_uuid = kwargs.get("enterprise_uuid", None)
users = []

try:
enterprise_customer_queryset = models.EnterpriseCustomerUser.objects.filter(
enterprise_customer__uuid=enterprise_uuid,
)
enterprise_customer_queryset = self.filter_queryset_by_email(enterprise_customer_queryset)
enterprise_customer_queryset = self.filter_queryset_by_user_query(
enterprise_customer_queryset
)
users.extend(enterprise_customer_queryset)

pending_enterprise_customer_queryset = models.PendingEnterpriseCustomerUser.objects.filter(
enterprise_customer__uuid=enterprise_uuid
).order_by('user_email')
pending_enterprise_customer_queryset = self.filter_queryset_by_email(
pending_enterprise_customer_queryset,
is_pending_user=True
pending_enterprise_customer_queryset = (
models.PendingEnterpriseCustomerUser.objects.filter(
enterprise_customer__uuid=enterprise_uuid
).order_by("user_email")
)
pending_enterprise_customer_queryset = self.filter_queryset_by_user_query(
pending_enterprise_customer_queryset, is_pending_user=True
)
users.extend(pending_enterprise_customer_queryset)

except ValidationError:
# did not find UUID match in either EnterpriseCustomerUser or PendingEnterpriseCustomerUser
return response.Response(
{'detail': 'Could not find enterprise uuid {}'.format(enterprise_uuid)},
status=status.HTTP_404_NOT_FOUND
{"detail": "Could not find enterprise uuid {}".format(enterprise_uuid)},
status=status.HTTP_404_NOT_FOUND,
)

# default sort criteria
is_reversed = False
sort_field = 'first_name'

ordering_criteria = self.request.query_params.get('ordering', None)

# apply pre-serialization ordering by user criteria before the users
# get divvied up by pagination
ordering_criteria = self.request.query_params.get("ordering", None)
if ordering_criteria:
is_reversed = '-' in ordering_criteria
sort_field = 'user_id'

# sort the users by default or specified criteria since the queryset will get
# split up during pagination and the post-serialization sort operations
# will be only applied to a single page of results
users = sorted(
users,
key=(
lambda k:
getattr(k, sort_field)
if hasattr(k, sort_field)
else k.id
),
reverse=is_reversed
)

# paginate the queryset
users_page = self.paginator.paginate_queryset(
users,
request,
view=self
)
users_page = self.paginator.paginate_queryset(users, request, view=self)

# serialize the paged dataset
serializer = serializers.EnterpriseUserSerializer(
users_page,
many=True
)
serializer = serializers.EnterpriseUserSerializer(users_page, many=True)
serializer_data = serializer.data

# apply pre-serialization ordering by user criteria before the users
# get divvied up by pagination
if ordering_criteria in ("administrator", "learner"):
serializer_data = sorted(
serializer_data,
key=lambda k: (
(k["is_admin"])
),
reverse=is_reversed
)
if ordering_criteria == "details":
serializer_data = sorted(
serializer_data,
key=lambda k: (
(
(
k["enterprise_customer_user"]["username"]
if k["enterprise_customer_user"] is not None
else k["pending_enterprise_customer_user"]["user_email"]
),
)
),
reverse=is_reversed,
)
# Apply post-serialization default ordering criteria (first by is_admin,
# then first name) only if user does not specify ordering criteria;
# Process this after the data has been serialized since the is_admin
Expand All @@ -159,10 +161,14 @@ def retrieve(self, request, *args, **kwargs):
key=lambda k: (
# sort by is_admin = True first (i.e. -1),
# then sort by first_name lexicographically
(-1 * k['is_admin'], k['enterprise_customer_user']['first_name'])
if k['enterprise_customer_user'] is not None
else -1 * k['is_admin']
)
(
-k["is_admin"],
(
k["enterprise_customer_user"]["username"]
if k["enterprise_customer_user"] is not None
else k["pending_enterprise_customer_user"]["user_email"]
),
)
),
)

return self.paginator.get_paginated_response(serializer_data)
38 changes: 38 additions & 0 deletions tests/test_enterprise/api/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9686,3 +9686,41 @@ def test_get_pending_enterprise_user(self):
response = self.client.get(settings.TEST_SERVER + url)

assert expected_json == response.json().get('results')[0]

def test_list_users_filtered(self):
"""
Test that the list support tool users endpoint can be filtered by user details
"""
user = factories.UserFactory()
user_2 = factories.UserFactory()

enterprise_customer = factories.EnterpriseCustomerFactory(uuid=FAKE_UUIDS[0])
enterprise_customer_user = factories.EnterpriseCustomerUserFactory(
user_id=user.id,
enterprise_customer=enterprise_customer
)
factories.EnterpriseCustomerUserFactory(
user_id=user_2.id,
enterprise_customer=enterprise_customer
)
expected_json = [{
'enterprise_customer_user': {
'id': user.id,
'username': user.username,
'first_name': user.first_name,
'last_name': user.last_name,
'email': user.email,
'is_staff': user.is_staff,
'is_active': user.is_active,
'date_joined': user.date_joined.strftime("%Y-%m-%dT%H:%M:%SZ"),
},
'pending_enterprise_customer_user': None,
'role_assignments': [ENTERPRISE_LEARNER_ROLE],
'is_admin': False
}]
user_query_string = f'?user_query={enterprise_customer_user.user_email}'
url = reverse(self.ECS_ENDPOINT, kwargs={self.ECS_KWARG: enterprise_customer.uuid}) + user_query_string
response = self.client.get(settings.TEST_SERVER + url)

assert expected_json == response.json().get('results')
assert response.json().get('count') == 1

0 comments on commit f8ea429

Please sign in to comment.