Merge pull request #2767 from bookwyrm-social/link-mention-clash

Clashes between links and mentions
This commit is contained in:
Mouse Reeve 2023-03-29 17:06:11 -07:00 committed by GitHub
commit b5d6c94885
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 49 additions and 18 deletions

View file

@ -456,6 +456,24 @@ http://www.fish.com/"""
views.status.format_links(url), f'<a href="{url}">{url[8:]}</a>' views.status.format_links(url), f'<a href="{url}">{url[8:]}</a>'
) )
def test_format_mentions_with_at_symbol_links(self, *_):
"""A link with an @username shouldn't treat the username as a mention"""
content = "a link to https://example.com/user/@mouse"
mentions = views.status.find_mentions(self.local_user, content)
self.assertEqual(
views.status.format_mentions(content, mentions),
"a link to https://example.com/user/@mouse",
)
def test_format_hashtag_with_pound_symbol_links(self, *_):
"""A link with an @username shouldn't treat the username as a mention"""
content = "a link to https://example.com/page#anchor"
hashtags = views.status.find_or_create_hashtags(content)
self.assertEqual(
views.status.format_hashtags(content, hashtags),
"a link to https://example.com/page#anchor",
)
def test_to_markdown(self, *_): def test_to_markdown(self, *_):
"""this is mostly handled in other places, but nonetheless""" """this is mostly handled in other places, but nonetheless"""
text = "_hi_ and http://fish.com is <marquee>rad</marquee>" text = "_hi_ and http://fish.com is <marquee>rad</marquee>"

View file

@ -96,34 +96,22 @@ class CreateStatus(View):
# inspect the text for user tags # inspect the text for user tags
content = status.content content = status.content
for (mention_text, mention_user) in find_mentions( mentions = find_mentions(request.user, content)
request.user, content for (_, mention_user) in mentions.items():
).items():
# add them to status mentions fk # add them to status mentions fk
status.mention_users.add(mention_user) status.mention_users.add(mention_user)
content = format_mentions(content, mentions)
# turn the mention into a link
content = re.sub(
rf"{mention_text}\b(?!@)",
rf'<a href="{mention_user.remote_id}">{mention_text}</a>',
content,
)
# add reply parent to mentions # add reply parent to mentions
if status.reply_parent: if status.reply_parent:
status.mention_users.add(status.reply_parent.user) status.mention_users.add(status.reply_parent.user)
# inspect the text for hashtags # inspect the text for hashtags
for (mention_text, mention_hashtag) in find_or_create_hashtags(content).items(): hashtags = find_or_create_hashtags(content)
for (_, mention_hashtag) in hashtags.items():
# add them to status mentions fk # add them to status mentions fk
status.mention_hashtags.add(mention_hashtag) status.mention_hashtags.add(mention_hashtag)
content = format_hashtags(content, hashtags)
# turn the mention into a link
content = re.sub(
rf"{mention_text}\b(?!@)",
rf'<a href="{mention_hashtag.remote_id}" data-mention="hashtag">'
+ rf"{mention_text}</a>",
content,
)
# deduplicate mentions # deduplicate mentions
status.mention_users.set(set(status.mention_users.all())) status.mention_users.set(set(status.mention_users.all()))
@ -150,6 +138,31 @@ class CreateStatus(View):
return redirect_to_referer(request) return redirect_to_referer(request)
def format_mentions(content, mentions):
"""Detect @mentions and make them links"""
for (mention_text, mention_user) in mentions.items():
# turn the mention into a link
content = re.sub(
rf"(?<!/)\B{mention_text}\b(?!@)",
rf'<a href="{mention_user.remote_id}">{mention_text}</a>',
content,
)
return content
def format_hashtags(content, hashtags):
"""Detect #hashtags and make them links"""
for (mention_text, mention_hashtag) in hashtags.items():
# turn the mention into a link
content = re.sub(
rf"(?<!/)\B{mention_text}\b(?!@)",
rf'<a href="{mention_hashtag.remote_id}" data-mention="hashtag">'
+ rf"{mention_text}</a>",
content,
)
return content
@method_decorator(login_required, name="dispatch") @method_decorator(login_required, name="dispatch")
class DeleteStatus(View): class DeleteStatus(View):
"""tombstone that bad boy""" """tombstone that bad boy"""