Attach mentions in ActivityPub outgoing payloads

Any mentions given in the _mentions list or found in the raw_content
are attached as Mention tags before sending.

https://git.feneas.org/socialhome/socialhome/issues/522
merge-requests/157/merge
Jason Robinson 2019-09-08 23:52:23 +03:00
rodzic c5297fd940
commit 8d2bc74556
4 zmienionych plików z 109 dodań i 3 usunięć

Wyświetl plik

@ -1,7 +1,7 @@
import logging
import re
import uuid
from typing import Dict, List, Set
from typing import Dict, List
from federation.entities.activitypub.constants import (
CONTEXTS_DEFAULT, CONTEXT_MANUALLY_APPROVES_FOLLOWERS, CONTEXT_SENSITIVE, CONTEXT_HASHTAG,
@ -13,7 +13,7 @@ from federation.entities.utils import get_base_attributes
from federation.outbound import handle_send
from federation.types import UserType
from federation.utils.django import get_configuration
from federation.utils.text import with_slash
from federation.utils.text import with_slash, validate_handle
logger = logging.getLogger("federation")
@ -23,6 +23,7 @@ class AttachImagesMixin(RawContentMixin):
"""
Attach any embedded images from raw_content.
"""
super().pre_send()
if self._media_type != "text/markdown":
return
regex = r"!\[([\w ]*)\]\((https?://[\w\d\-\./]+\.[\w]*((?<=jpg)|(?<=gif)|(?<=png)|(?<=jpeg)))\)"
@ -59,6 +60,7 @@ class CleanContentMixin(RawContentMixin):
def cleaner(match):
return f"#{match.groups()[0]}"
super().post_receive()
self.raw_content = re.sub(
r'\[#([\w\-_]+)\]\(http?s://[a-zA-Z0-9/._-]+\)',
cleaner,
@ -122,6 +124,10 @@ class ActivitypubNoteMixin(AttachImagesMixin, CleanContentMixin, ActivitypubEnti
if tag.get('type') == "Mention" and tag.get('href'):
self._mentions.add(tag.get('href'))
def pre_send(self):
super().pre_send()
self.extract_mentions()
def to_as2(self) -> Dict:
as2 = {
"@context": CONTEXTS_DEFAULT + [
@ -146,15 +152,35 @@ class ActivitypubNoteMixin(AttachImagesMixin, CleanContentMixin, ActivitypubEnti
'content': self.raw_content,
'mediaType': self._media_type,
},
"tag": [],
},
"published": self.created_at.isoformat(),
}
if len(self._children):
as2["object"]["attachment"] = []
for child in self._children:
as2["object"]["attachment"].append(child.to_as2())
as2["object"]["tag"] = self.add_object_tags()
if len(self._mentions):
mentions = list(self._mentions)
mentions.sort()
for mention in mentions:
if mention.startswith("http"):
as2["object"]["tag"].append({
'type': 'Mention',
'href': mention,
'name': mention,
})
elif validate_handle(mention):
# Look up via WebFinger
as2["object"]["tag"].append({
'type': 'Mention',
'href': mention, # TODO need to implement fetch via webfinger for AP handles first
'name': mention,
})
as2["object"]["tag"].extend(self.add_object_tags())
return as2
@ -172,6 +198,7 @@ class ActivitypubFollow(ActivitypubEntityMixin, Follow):
"""
Post receive hook - send back follow ack.
"""
super().post_receive()
if not self.following:
return

Wyświetl plik

@ -51,6 +51,18 @@ class BaseEntity:
klass = getattr(entities, f"{protocol.title()}{self.__class__.__name__}")
return klass.from_base(self)
def post_receive(self):
"""
Run any actions after deserializing the payload into an entity.
"""
pass
def pre_send(self):
"""
Run any actions before serializing the entity for sending.
"""
pass
def validate(self):
"""Do validation.

Wyświetl plik

@ -127,6 +127,56 @@ class TestEntitiesConvertToAS2:
'published': '2019-04-27T00:00:00',
}
def test_post_to_as2__with_mentions(self, activitypubpost_mentions):
activitypubpost_mentions.pre_send()
result = activitypubpost_mentions.to_as2()
assert result == {
'@context': [
'https://www.w3.org/ns/activitystreams',
{"pyfed": "https://docs.jasonrobinson.me/ns/python-federation"},
{'Hashtag': 'as:Hashtag'},
'https://w3id.org/security/v1',
{'sensitive': 'as:sensitive'},
],
'type': 'Create',
'id': 'http://127.0.0.1:8000/post/123456/#create',
'actor': 'http://127.0.0.1:8000/profile/123456/',
'object': {
'id': 'http://127.0.0.1:8000/post/123456/',
'type': 'Note',
'attributedTo': 'http://127.0.0.1:8000/profile/123456/',
'content': """<h1>raw_content</h1>
<p>@{someone@localhost.local}</p>""",
'published': '2019-04-27T00:00:00',
'inReplyTo': None,
'sensitive': False,
'summary': None,
'tag': [
{
"type": "Mention",
"href": "http://127.0.0.1:8000/profile/999999",
"name": "http://127.0.0.1:8000/profile/999999",
},
{
"type": "Mention",
"href": "jaywink@localhost.local",
"name": "jaywink@localhost.local",
},
{
"type": "Mention",
"href": "someone@localhost.local",
"name": "someone@localhost.local",
},
],
'url': '',
'source': {
'content': '# raw_content\n\n@{someone@localhost.local}',
'mediaType': 'text/markdown',
},
},
'published': '2019-04-27T00:00:00',
}
def test_post_to_as2__with_tags(self, activitypubpost_tags):
result = activitypubpost_tags.to_as2()
assert result == {

Wyświetl plik

@ -87,6 +87,23 @@ def activitypubpost_images():
)
@pytest.fixture
def activitypubpost_mentions():
with freeze_time("2019-04-27"):
return ActivitypubPost(
raw_content="""# raw_content\n\n@{someone@localhost.local}""",
public=True,
provider_display_name="Socialhome",
id=f"http://127.0.0.1:8000/post/123456/",
activity_id=f"http://127.0.0.1:8000/post/123456/#create",
actor_id=f"http://127.0.0.1:8000/profile/123456/",
_mentions={
"http://127.0.0.1:8000/profile/999999",
"jaywink@localhost.local",
}
)
@pytest.fixture
def activitypubpost_tags():
with freeze_time("2019-04-27"):