Add `process_text_links` text utility to linkify URL's in text

Moved from Socialhome.
merge-requests/159/merge
Jason Robinson 2020-01-26 01:08:54 +02:00
rodzic 5ab541440d
commit 47d3d53a18
4 zmienionych plików z 53 dodań i 1 usunięć

Wyświetl plik

@ -8,6 +8,8 @@
If Django is configured, a profile will be retrieved using the configured profile If Django is configured, a profile will be retrieved using the configured profile
getter function and the profile name or username will be used for the link. getter function and the profile name or username will be used for the link.
* Add `process_text_links` text utility to linkify URL's in text.
### Changed ### Changed

Wyświetl plik

@ -1,4 +1,4 @@
from federation.utils.text import decode_if_bytes, encode_if_text, validate_handle from federation.utils.text import decode_if_bytes, encode_if_text, validate_handle, process_text_links
def test_decode_if_bytes(): def test_decode_if_bytes():
@ -11,6 +11,29 @@ def test_encode_if_text():
assert encode_if_text("foobar") == b"foobar" assert encode_if_text("foobar") == b"foobar"
class TestProcessTextLinks:
def test_link_at_start_or_end(self):
assert process_text_links('https://example.org example.org\nhttp://example.org') == \
'<a href="https://example.org" rel="nofollow" target="_blank">https://example.org</a> ' \
'<a href="http://example.org" rel="nofollow" target="_blank">example.org</a>\n' \
'<a href="http://example.org" rel="nofollow" target="_blank">http://example.org</a>'
def test_existing_links_get_attrs_added(self):
assert process_text_links('<a href="https://example.org">https://example.org</a>') == \
'<a href="https://example.org" rel="nofollow" target="_blank">https://example.org</a>'
def test_code_sections_are_skipped(self):
assert process_text_links('<code>https://example.org</code><code>\nhttps://example.org\n</code>') == \
'<code>https://example.org</code><code>\nhttps://example.org\n</code>'
def test_emails_are_skipped(self):
assert process_text_links('foo@example.org') == 'foo@example.org'
def test_does_not_add_target_blank_if_link_is_internal(self):
assert process_text_links('<a href="/streams/tag/foobar">#foobar</a>') == \
'<a href="/streams/tag/foobar">#foobar</a>'
def test_validate_handle(): def test_validate_handle():
assert validate_handle("foo@bar.com") assert validate_handle("foo@bar.com")
assert validate_handle("Foo@baR.com") assert validate_handle("Foo@baR.com")

Wyświetl plik

@ -1,6 +1,9 @@
import re import re
from urllib.parse import urlparse from urllib.parse import urlparse
import bleach
from bleach import callbacks
def decode_if_bytes(text): def decode_if_bytes(text):
try: try:
@ -24,6 +27,29 @@ def get_path_from_url(url: str) -> str:
return parsed.path return parsed.path
def process_text_links(text):
"""Process links in text, adding some attributes and linkifying textual links."""
link_callbacks = [callbacks.nofollow, callbacks.target_blank]
def link_attributes(attrs, new=False):
"""Run standard callbacks except for internal links."""
href_key = (None, "href")
if attrs.get(href_key).startswith("/"):
return attrs
# Run the standard callbacks
for callback in link_callbacks:
attrs = callback(attrs, new)
return attrs
return bleach.linkify(
text,
callbacks=[link_attributes],
parse_email=False,
skip_tags=["code"],
)
def validate_handle(handle): def validate_handle(handle):
""" """
Very basic handle validation as per Very basic handle validation as per

Wyświetl plik

@ -28,6 +28,7 @@ setup(
license="BSD 3-clause", license="BSD 3-clause",
install_requires=[ install_requires=[
"attrs", "attrs",
"bleach>3.0",
"commonmark", "commonmark",
"cryptography", "cryptography",
"cssselect>=0.9.2", "cssselect>=0.9.2",