From d418e41f7ee03b80d7f3fd6e7a50d2aebd997c97 Mon Sep 17 00:00:00 2001 From: Ryan Petrello Date: Wed, 18 Jan 2017 08:54:24 -0500 Subject: [PATCH] Properly encode prev/next pagination links when URL contains unicode chars. Resolves #4767 --- awx/api/pagination.py | 2 + awx/main/tests/functional/test_projects.py | 80 ++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/awx/api/pagination.py b/awx/api/pagination.py index b6463ce515..9a416e9995 100644 --- a/awx/api/pagination.py +++ b/awx/api/pagination.py @@ -16,6 +16,7 @@ class Pagination(pagination.PageNumberPagination): if not self.page.has_next(): return None url = self.request and self.request.get_full_path() or '' + url = url.encode('utf-8') page_number = self.page.next_page_number() return replace_query_param(url, self.page_query_param, page_number) @@ -23,5 +24,6 @@ class Pagination(pagination.PageNumberPagination): if not self.page.has_previous(): return None url = self.request and self.request.get_full_path() or '' + url = url.encode('utf-8') page_number = self.page.previous_page_number() return replace_query_param(url, self.page_query_param, page_number) diff --git a/awx/main/tests/functional/test_projects.py b/awx/main/tests/functional/test_projects.py index 8d93fcf6d9..8b66c396bd 100644 --- a/awx/main/tests/functional/test_projects.py +++ b/awx/main/tests/functional/test_projects.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + import mock # noqa import pytest @@ -22,6 +24,84 @@ def team_project_list(organization_factory): return objects +@pytest.mark.django_db +def test_user_project_paged_list(get, organization_factory): + 'Test project listing that spans multiple pages' + + # 3 total projects, 1 per page, 3 pages + objects = organization_factory( + 'org1', + projects=['project-%s' % i for i in range(3)], + users=['alice'], + roles=['project-%s.admin_role:alice' % i for i in range(3)], + ) + + # first page has first project and no previous page + pk = objects.users.alice.pk + url = reverse('api:user_projects_list', args=(pk,)) + results = get(url, objects.users.alice, QUERY_STRING='page_size=1').data + assert results['count'] == 3 + assert len(results['results']) == 1 + assert results['previous'] is None + assert results['next'] == ( + '/api/v1/users/%s/projects/?page=2&page_size=1' % pk + ) + + # second page has one more, a previous and next page + results = get(url, objects.users.alice, + QUERY_STRING='page=2&page_size=1').data + assert len(results['results']) == 1 + assert results['previous'] == ( + '/api/v1/users/%s/projects/?page=1&page_size=1' % pk + ) + assert results['next'] == ( + '/api/v1/users/%s/projects/?page=3&page_size=1' % pk + ) + + # third page has last project and a previous page + results = get(url, objects.users.alice, + QUERY_STRING='page=3&page_size=1').data + assert len(results['results']) == 1 + assert results['previous'] == ( + '/api/v1/users/%s/projects/?page=2&page_size=1' % pk + ) + assert results['next'] is None + + +@pytest.mark.django_db +def test_user_project_paged_list_with_unicode(get, organization_factory): + 'Test project listing that contains unicode chars in the next/prev links' + + # Create 2 projects that contain a "cloud" unicode character, make sure we + # can search it and properly generate next/previous page links + objects = organization_factory( + 'org1', + projects=['project-☁-1','project-☁-2'], + users=['alice'], + roles=['project-☁-1.admin_role:alice','project-☁-2.admin_role:alice'], + ) + pk = objects.users.alice.pk + url = reverse('api:user_projects_list', args=(pk,)) + + # first on first page, next page link contains unicode char + results = get(url, objects.users.alice, + QUERY_STRING='page_size=1&search=%E2%98%81').data + assert results['count'] == 2 + assert len(results['results']) == 1 + assert results['next'] == ( + '/api/v1/users/%s/projects/?page=2&page_size=1&search=%%E2%%98%%81' % pk # noqa + ) + + # second project on second page, previous page link contains unicode char + results = get(url, objects.users.alice, + QUERY_STRING='page=2&page_size=1&search=%E2%98%81').data + assert results['count'] == 2 + assert len(results['results']) == 1 + assert results['previous'] == ( + '/api/v1/users/%s/projects/?page=1&page_size=1&search=%%E2%%98%%81' % pk # noqa + ) + + @pytest.mark.django_db def test_user_project_list(get, organization_factory): 'List of projects a user has access to, filtered by projects you can also see'