Fix #923: Use same markdown widget for all content fields (rules, description, reports, notes, etc.)
This commit is contained in:
parent
8d29adf6be
commit
7850ca3e1c
12 changed files with 130 additions and 77 deletions
|
|
@ -250,36 +250,42 @@ def join_queries_or(left, right):
|
|||
|
||||
|
||||
def render_markdown(text):
|
||||
return markdown.markdown(text, extensions=["nl2br"])
|
||||
return markdown.markdown(text, extensions=["nl2br", "extra"])
|
||||
|
||||
|
||||
HTMl_CLEANER = bleach.sanitizer.Cleaner(
|
||||
SAFE_TAGS = [
|
||||
"p",
|
||||
"a",
|
||||
"abbr",
|
||||
"acronym",
|
||||
"b",
|
||||
"blockquote",
|
||||
"code",
|
||||
"em",
|
||||
"i",
|
||||
"li",
|
||||
"ol",
|
||||
"strong",
|
||||
"ul",
|
||||
]
|
||||
HTMl_CLEANER = bleach.sanitizer.Cleaner(strip=True, tags=SAFE_TAGS)
|
||||
|
||||
HTML_PERMISSIVE_CLEANER = bleach.sanitizer.Cleaner(
|
||||
strip=True,
|
||||
tags=[
|
||||
"p",
|
||||
"a",
|
||||
"abbr",
|
||||
"acronym",
|
||||
"b",
|
||||
"blockquote",
|
||||
"code",
|
||||
"em",
|
||||
"i",
|
||||
"li",
|
||||
"ol",
|
||||
"strong",
|
||||
"ul",
|
||||
],
|
||||
tags=SAFE_TAGS + ["h1", "h2", "h3", "h4", "h5", "h6", "div", "section", "article"],
|
||||
attributes=["class", "rel", "alt", "title"],
|
||||
)
|
||||
|
||||
HTML_LINKER = bleach.linkifier.Linker()
|
||||
|
||||
|
||||
def clean_html(html):
|
||||
return HTMl_CLEANER.clean(html)
|
||||
def clean_html(html, permissive=False):
|
||||
return (
|
||||
HTML_PERMISSIVE_CLEANER.clean(html) if permissive else HTMl_CLEANER.clean(html)
|
||||
)
|
||||
|
||||
|
||||
def render_html(text, content_type):
|
||||
def render_html(text, content_type, permissive=False):
|
||||
rendered = render_markdown(text)
|
||||
if content_type == "text/html":
|
||||
rendered = text
|
||||
|
|
@ -288,7 +294,7 @@ def render_html(text, content_type):
|
|||
else:
|
||||
rendered = render_markdown(text)
|
||||
rendered = HTML_LINKER.linkify(rendered)
|
||||
return clean_html(rendered).strip().replace("\n", "")
|
||||
return clean_html(rendered, permissive=permissive).strip().replace("\n", "")
|
||||
|
||||
|
||||
def render_plain_text(html):
|
||||
|
|
|
|||
|
|
@ -191,5 +191,10 @@ class TextPreviewView(views.APIView):
|
|||
if "text" not in payload:
|
||||
return response.Response({"detail": "Invalid input"}, status=400)
|
||||
|
||||
data = {"rendered": utils.render_html(payload["text"], "text/markdown")}
|
||||
permissive = payload.get("permissive", False)
|
||||
data = {
|
||||
"rendered": utils.render_html(
|
||||
payload["text"], "text/markdown", permissive=permissive
|
||||
)
|
||||
}
|
||||
return response.Response(data, status=200)
|
||||
|
|
|
|||
|
|
@ -38,9 +38,7 @@ class InstanceLongDescription(types.StringPreference):
|
|||
name = "long_description"
|
||||
verbose_name = "Long description"
|
||||
default = ""
|
||||
help_text = (
|
||||
"Instance long description, displayed in the about page (markdown allowed)."
|
||||
)
|
||||
help_text = "Instance long description, displayed in the about page."
|
||||
widget = widgets.Textarea
|
||||
field_kwargs = {"required": False}
|
||||
|
||||
|
|
@ -52,9 +50,7 @@ class InstanceTerms(types.StringPreference):
|
|||
name = "terms"
|
||||
verbose_name = "Terms of service"
|
||||
default = ""
|
||||
help_text = (
|
||||
"Terms of service and privacy policy for your instance (markdown allowed)."
|
||||
)
|
||||
help_text = "Terms of service and privacy policy for your instance."
|
||||
widget = widgets.Textarea
|
||||
field_kwargs = {"required": False}
|
||||
|
||||
|
|
@ -66,7 +62,7 @@ class InstanceRules(types.StringPreference):
|
|||
name = "rules"
|
||||
verbose_name = "Rules"
|
||||
default = ""
|
||||
help_text = "Rules/Code of Conduct (markdown allowed)."
|
||||
help_text = "Rules/Code of Conduct."
|
||||
widget = widgets.Textarea
|
||||
field_kwargs = {"required": False}
|
||||
|
||||
|
|
|
|||
|
|
@ -103,27 +103,40 @@ def test_join_url(start, end, expected):
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"text, content_type, expected",
|
||||
"text, content_type, permissive, expected",
|
||||
[
|
||||
("hello world", "text/markdown", "<p>hello world</p>"),
|
||||
("hello world", "text/plain", "<p>hello world</p>"),
|
||||
("<strong>hello world</strong>", "text/html", "<strong>hello world</strong>"),
|
||||
("hello world", "text/markdown", False, "<p>hello world</p>"),
|
||||
("hello world", "text/plain", False, "<p>hello world</p>"),
|
||||
(
|
||||
"<strong>hello world</strong>",
|
||||
"text/html",
|
||||
False,
|
||||
"<strong>hello world</strong>",
|
||||
),
|
||||
# images and other non whitelisted html should be removed
|
||||
("hello world\n", "text/markdown", "<p>hello world</p>"),
|
||||
("hello world\n", "text/markdown", False, "<p>hello world</p>"),
|
||||
(
|
||||
"hello world\n\n<script></script>\n\n<style></style>",
|
||||
"text/markdown",
|
||||
False,
|
||||
"<p>hello world</p>",
|
||||
),
|
||||
(
|
||||
"<p>hello world</p><script></script>\n\n<style></style>",
|
||||
"text/html",
|
||||
False,
|
||||
"<p>hello world</p>",
|
||||
),
|
||||
(
|
||||
'<p class="foo">hello world</p><script></script>\n\n<style></style>',
|
||||
"text/markdown",
|
||||
True,
|
||||
'<p class="foo">hello world</p>',
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_render_html(text, content_type, expected):
|
||||
result = utils.render_html(text, content_type)
|
||||
def test_render_html(text, content_type, permissive, expected):
|
||||
result = utils.render_html(text, content_type, permissive=permissive)
|
||||
assert result == expected
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -281,3 +281,15 @@ def test_can_render_text_preview(api_client, db):
|
|||
expected = {"rendered": utils.render_html(payload["text"], "text/markdown")}
|
||||
assert response.status_code == 200
|
||||
assert response.data == expected
|
||||
|
||||
|
||||
def test_can_render_text_preview_permissive(api_client, db):
|
||||
payload = {"text": "Hello world", "permissive": True}
|
||||
url = reverse("api:v1:text-preview")
|
||||
response = api_client.post(url, payload)
|
||||
|
||||
expected = {
|
||||
"rendered": utils.render_html(payload["text"], "text/markdown", permissive=True)
|
||||
}
|
||||
assert response.status_code == 200
|
||||
assert response.data == expected
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue