diff --git a/swh/web/browse/snapshot_context.py b/swh/web/browse/snapshot_context.py --- a/swh/web/browse/snapshot_context.py +++ b/swh/web/browse/snapshot_context.py @@ -1135,7 +1135,7 @@ query_params["per_page"] = per_page revs_ordering = request.GET.get("revs_ordering", "") - query_params["revs_ordering"] = revs_ordering + query_params["revs_ordering"] = revs_ordering or None if origin_info: browse_view_name = "browse-origin-log" diff --git a/swh/web/browse/views/revision.py b/swh/web/browse/views/revision.py --- a/swh/web/browse/views/revision.py +++ b/swh/web/browse/views/revision.py @@ -262,7 +262,7 @@ query_params={ "per_page": per_page, "offset": offset + per_page, - "revs_ordering": revs_ordering, + "revs_ordering": revs_ordering or None, }, ) @@ -274,7 +274,7 @@ query_params={ "per_page": per_page, "offset": offset - per_page, - "revs_ordering": revs_ordering, + "revs_ordering": revs_ordering or None, }, ) diff --git a/swh/web/common/utils.py b/swh/web/common/utils.py --- a/swh/web/common/utils.py +++ b/swh/web/common/utils.py @@ -80,7 +80,7 @@ ) if query_params: - query_params = {k: v for k, v in query_params.items() if v} + query_params = {k: v for k, v in query_params.items() if v is not None} if query_params and len(query_params) > 0: query_dict = QueryDict("", mutable=True) diff --git a/swh/web/tests/browse/views/test_revision.py b/swh/web/tests/browse/views/test_revision.py --- a/swh/web/tests/browse/views/test_revision.py +++ b/swh/web/tests/browse/views/test_revision.py @@ -57,7 +57,7 @@ next_page_url = reverse( "browse-revision-log", url_args={"sha1_git": revision}, - query_params={"offset": per_page, "per_page": per_page}, + query_params={"offset": per_page, "per_page": per_page,}, ) nb_log_entries = per_page @@ -91,7 +91,7 @@ prev_page_url = reverse( "browse-revision-log", url_args={"sha1_git": revision}, - query_params={"per_page": per_page}, + query_params={"offset": 0, "per_page": per_page}, ) next_page_url = reverse( "browse-revision-log", diff --git a/swh/web/tests/common/test_utils.py b/swh/web/tests/common/test_utils.py --- a/swh/web/tests/common/test_utils.py +++ b/swh/web/tests/common/test_utils.py @@ -4,9 +4,14 @@ # See top-level LICENSE file for more information import datetime +from urllib.parse import quote import pytest +from django.conf.urls import url +from django.test.utils import override_settings +from django.urls.exceptions import NoReverseMatch + from swh.web.common import utils from swh.web.common.exc import BadInputExc @@ -138,3 +143,93 @@ ) assert utils.rst_to_html(rst) == expected_html + + +def sample_test_view(request, string, number): + pass + + +def sample_test_view_no_url_args(request): + pass + + +urlpatterns = [ + url( + r"^sample/test/(?P.+)/view/(?P[0-9]+)/$", + sample_test_view, + name="sample-test-view", + ), + url( + r"^sample/test/view/no/url/args/$", + sample_test_view_no_url_args, + name="sample-test-view-no-url-args", + ), +] + + +@override_settings(ROOT_URLCONF=__name__) +def test_reverse_url_args_only_ok(): + string = "foo" + number = 55 + url = utils.reverse( + "sample-test-view", url_args={"string": string, "number": number} + ) + assert url == f"/sample/test/{string}/view/{number}/" + + +@override_settings(ROOT_URLCONF=__name__) +def test_reverse_url_args_only_ko(): + string = "foo" + with pytest.raises(NoReverseMatch): + utils.reverse("sample-test-view", url_args={"string": string, "number": string}) + + +@override_settings(ROOT_URLCONF=__name__) +def test_reverse_no_url_args(): + url = utils.reverse("sample-test-view-no-url-args") + assert url == "/sample/test/view/no/url/args/" + + +@override_settings(ROOT_URLCONF=__name__) +def test_reverse_query_params_only(): + start = 0 + scope = "foo" + url = utils.reverse( + "sample-test-view-no-url-args", query_params={"start": start, "scope": scope} + ) + assert url == f"/sample/test/view/no/url/args/?scope={scope}&start={start}" + + url = utils.reverse( + "sample-test-view-no-url-args", query_params={"start": start, "scope": None} + ) + assert url == f"/sample/test/view/no/url/args/?start={start}" + + +@override_settings(ROOT_URLCONF=__name__) +def test_reverse_query_params_encode(): + libname = "libstc++" + url = utils.reverse( + "sample-test-view-no-url-args", query_params={"libname": libname} + ) + assert url == f"/sample/test/view/no/url/args/?libname={quote(libname, safe='/;:')}" + + +@override_settings(ROOT_URLCONF=__name__) +def test_reverse_url_args_query_params(): + string = "foo" + number = 55 + start = 10 + scope = "bar" + url = utils.reverse( + "sample-test-view", + url_args={"string": string, "number": number}, + query_params={"start": start, "scope": scope}, + ) + assert url == f"/sample/test/{string}/view/{number}/?scope={scope}&start={start}" + + +@override_settings(ROOT_URLCONF=__name__) +def test_reverse_absolute_uri(request_factory): + request = request_factory.get(utils.reverse("sample-test-view-no-url-args")) + url = utils.reverse("sample-test-view-no-url-args", request=request) + assert url == f"http://{request.META['SERVER_NAME']}/sample/test/view/no/url/args/"