Fixed #559: Trim hashtags to 100 chars or less

This commit is contained in:
Andrew Godwin 2023-05-03 23:11:34 -06:00
parent ac41f2afde
commit 90e8a6d6c0
3 changed files with 43 additions and 5 deletions

View file

@ -87,6 +87,8 @@ class HashtagManager(models.Manager):
class Hashtag(StatorModel):
MAXIMUM_LENGTH = 100
# Normalized hashtag without the '#'
hashtag = models.SlugField(primary_key=True, max_length=100)

View file

@ -489,7 +489,10 @@ class Post(StatorModel):
# Strip all unwanted HTML and apply linebreaks filter, grabbing hashtags on the way
parser = FediverseHtmlParser(linebreaks_filter(content), find_hashtags=True)
content = parser.html
hashtags = sorted(parser.hashtags) or None
hashtags = (
sorted([tag[: Hashtag.MAXIMUM_LENGTH] for tag in parser.hashtags])
or None
)
# Make the Post object
post = cls.objects.create(
author=author,
@ -529,7 +532,10 @@ class Post(StatorModel):
# Strip all HTML and apply linebreaks filter
parser = FediverseHtmlParser(linebreaks_filter(content), find_hashtags=True)
self.content = parser.html
self.hashtags = sorted(parser.hashtags) or None
self.hashtags = (
sorted([tag[: Hashtag.MAXIMUM_LENGTH] for tag in parser.hashtags])
or None
)
self.summary = summary or None
self.sensitive = bool(summary) if sensitive is None else sensitive
self.visibility = visibility
@ -577,7 +583,7 @@ class Post(StatorModel):
if self.hashtags:
for hashtag in self.hashtags:
tag, _ = await Hashtag.objects.aget_or_create(
hashtag=hashtag,
hashtag=hashtag[: Hashtag.MAXIMUM_LENGTH],
)
await tag.atransition_perform(HashtagStates.outdated)
@ -876,7 +882,9 @@ class Post(StatorModel):
post.mentions.add(mention_identity)
elif tag_type in ["_:hashtag", "hashtag"]:
post.hashtags.append(
get_value_or_map(tag, "name", "nameMap").lower().lstrip("#")
get_value_or_map(tag, "name", "nameMap")
.lower()
.lstrip("#")[: Hashtag.MAXIMUM_LENGTH]
)
elif tag_type in ["toot:emoji", "emoji"]:
emoji = Emoji.by_ap_tag(post.author.domain, tag, create=True)

View file

@ -1,7 +1,7 @@
import pytest
from pytest_httpx import HTTPXMock
from activities.models import Post, PostStates
from activities.models import Hashtag, Post, PostStates
from activities.models.post_types import QuestionData
from users.models import Identity, InboxMessage
@ -57,6 +57,34 @@ def test_post_create_edit(identity: Identity, config_system):
assert list(post.mentions.all()) == []
@pytest.mark.django_db
def test_ensure_hashtag(identity: Identity, config_system, stator):
"""
Tests that normal hashtags get a Hashtag object created, and a hashtag
over our limit of 100 characters is truncated.
"""
# Normal length hashtag
post = Post.create_local(
author=identity,
content="Hello, #testtag",
)
stator.run_single_cycle_sync()
assert post.hashtags == ["testtag"]
assert Hashtag.objects.filter(hashtag="testtag").exists()
# Excessively long hashtag
post = Post.create_local(
author=identity,
content="Hello, #thisisahashtagthatiswaytoolongandissignificantlyaboveourmaximumlimitofonehundredcharacterswhytheywouldbethislongidontknow",
)
stator.run_single_cycle_sync()
assert post.hashtags == [
"thisisahashtagthatiswaytoolongandissignificantlyaboveourmaximumlimitofonehundredcharacterswhytheywou"
]
assert Hashtag.objects.filter(
hashtag="thisisahashtagthatiswaytoolongandissignificantlyaboveourmaximumlimitofonehundredcharacterswhytheywou"
).exists()
@pytest.mark.django_db
def test_linkify_mentions_remote(
identity, identity2, remote_identity, remote_identity2