diff --git a/swh/web/common/swh_templatetags.py b/swh/web/common/swh_templatetags.py index 1edbd632..627b2050 100644 --- a/swh/web/common/swh_templatetags.py +++ b/swh/web/common/swh_templatetags.py @@ -1,153 +1,149 @@ # Copyright (C) 2017-2021 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information import json import re from django import template from django.utils.safestring import mark_safe from swh.web.common.converters import SWHDjangoJSONEncoder from swh.web.common.origin_save import get_savable_visit_types from swh.web.common.utils import rst_to_html register = template.Library() @register.filter def docstring_display(docstring): """ Utility function to htmlize reST-formatted documentation in browsable api. """ return rst_to_html(docstring) @register.filter def urlize_links_and_mails(text): """Utility function for decorating api links in browsable api. Args: text: whose content matching links should be transformed into contextual API or Browse html links. Returns The text transformed if any link is found. The text as is otherwise. """ if 'href="' not in text: text = re.sub(r"(http.*)", r'\1', text) return re.sub(r'([^ <>"]+@[^ <>"]+)', r'\1', text) return text @register.filter def urlize_header_links(text): """Utility function for decorating headers links in browsable api. Args text: Text whose content contains Link header value Returns: The text transformed with html link if any link is found. The text as is otherwise. """ - links = text.split(",") - ret = "" - for i, link in enumerate(links): - ret += re.sub(r"<(http.*)>", r'<\1>', link) - # add one link per line and align them - if i != len(links) - 1: - ret += "\n " - return ret + ret = re.sub( + r'<(http[^<>]+)>; rel="([^,]+)"', r'<\1>; rel="\2"\n', text + ).replace("\n,", "\n") + return ret[:-1] @register.filter def jsonify(obj): """Utility function for converting a django template variable to JSON in order to use it in script tags. Args obj: Any django template context variable Returns: JSON representation of the variable. """ return mark_safe(json.dumps(obj, cls=SWHDjangoJSONEncoder)) @register.filter def sub(value, arg): """Django template filter for subtracting two numbers Args: value (int/float): the value to subtract from arg (int/float): the value to subtract to Returns: int/float: The subtraction result """ return value - arg @register.filter def mul(value, arg): """Django template filter for multiplying two numbers Args: value (int/float): the value to multiply from arg (int/float): the value to multiply with Returns: int/float: The multiplication result """ return value * arg @register.filter def key_value(dict, key): """Django template filter to get a value in a dictionary. Args: dict (dict): a dictionary key (str): the key to lookup value Returns: The requested value in the dictionary """ return dict[key] @register.filter def visit_type_savable(visit_type: str) -> bool: """Django template filter to check if a save request can be created for a given visit type. Args: visit_type: the type of visit Returns: If the visit type is saveable or not """ return visit_type in get_savable_visit_types() @register.filter def split(value, arg): """Django template filter to split a string. Args: value (str): the string to split arg (str): the split separator Returns: list: the split string parts """ return value.split(arg) diff --git a/swh/web/tests/common/test_templatetags.py b/swh/web/tests/common/test_templatetags.py index 1e1e99e3..a3f60025 100644 --- a/swh/web/tests/common/test_templatetags.py +++ b/swh/web/tests/common/test_templatetags.py @@ -1,66 +1,80 @@ # Copyright (C) 2015-2019 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information +import pytest + +from swh.web.api.apiresponse import compute_link_header from swh.web.common.swh_templatetags import ( docstring_display, urlize_header_links, urlize_links_and_mails, ) def test_urlize_http_link(): link = "https://example.com/api/1/abc/" expected_content = f'{link}' assert urlize_links_and_mails(link) == expected_content def test_urlize_email(): email = "someone@example.com" expected_content = f'{email}' assert urlize_links_and_mails(email) == expected_content -def test_urlize_header_links(): +@pytest.mark.parametrize( + "next_link, prev_link", + [ + ("https://example.org/api/1/abc/", "https://example.org/api/1/def/"), + ("https://example.org/api/1/0,5/", "https://example.org/api/1/5,10/"), + ], +) +def test_urlize_header_links(next_link, prev_link): - next_link = "https://example.com/api/1/abc/" - prev_link = "https://example.com/api/1/def/" + link_header = f'<{next_link}>; rel="next",<{prev_link}>; rel="previous"' - content = f'<{next_link}>; rel="next"\n<{prev_link}>; rel="prev"' + assert ( + link_header + == compute_link_header( + {"headers": {"link-next": next_link, "link-prev": prev_link}}, options={} + )["Link"] + ) expected_content = ( f'<{next_link}>; rel="next"\n' - f'<{prev_link}>; rel="prev"' + f'<{prev_link}>; rel="previous"' ) - assert urlize_header_links(content) == expected_content + assert urlize_header_links(link_header) == expected_content def test_docstring_display(): # update api link with html links content with links docstring = ( "This is my list header:\n\n" " - Here is item 1, with a continuation\n" " line right here\n" " - Here is item 2\n\n" " Here is something that is not part of the list" ) expected_docstring = ( '
' "

This is my list header:

\n" "
\n" '\n" "

Here is something that is not part of the list

\n" "
\n" "
" ) assert docstring_display(docstring) == expected_docstring