Extract mentions from ActivityPub payload content

merge-requests/157/merge
Jason Robinson 2019-09-08 02:21:08 +03:00
rodzic 7e93dc3da3
commit c3fd773f78
5 zmienionych plików z 76 dodań i 6 usunięć

Wyświetl plik

@ -1,7 +1,7 @@
import logging import logging
import re import re
import uuid import uuid
from typing import Dict, List from typing import Dict, List, Set
from federation.entities.activitypub.constants import ( from federation.entities.activitypub.constants import (
CONTEXTS_DEFAULT, CONTEXT_MANUALLY_APPROVES_FOLLOWERS, CONTEXT_SENSITIVE, CONTEXT_HASHTAG, CONTEXTS_DEFAULT, CONTEXT_MANUALLY_APPROVES_FOLLOWERS, CONTEXT_SENSITIVE, CONTEXT_HASHTAG,
@ -109,6 +109,20 @@ class ActivitypubNoteMixin(AttachImagesMixin, CleanContentMixin, ActivitypubEnti
tags.append(_tag) tags.append(_tag)
return tags return tags
def extract_mentions(self) -> Set:
"""
Extract mentions from the source object.
"""
if not isinstance(self._source_object, dict):
return set()
_mentions = set()
source = self._source_object.get('object') if isinstance(self._source_object.get('object'), dict) else \
self._source_object
for tag in source.get('tag', []):
if tag.get('type') == "Mention" and tag.get('href'):
_mentions.add(tag.get('href'))
return _mentions
def to_as2(self) -> Dict: def to_as2(self) -> Dict:
as2 = { as2 = {
"@context": CONTEXTS_DEFAULT + [ "@context": CONTEXTS_DEFAULT + [

Wyświetl plik

@ -1,4 +1,5 @@
import re import re
from typing import Set
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
from lxml import etree from lxml import etree
@ -14,7 +15,7 @@ class DiasporaEntityMixin(BaseEntity):
# Normally outbound document is generated from entity. Store one here if at some point we already have a doc # Normally outbound document is generated from entity. Store one here if at some point we already have a doc
outbound_doc = None outbound_doc = None
def extract_mentions(self): def extract_mentions(self) -> Set:
""" """
Extract mentions from an entity with ``raw_content``. Extract mentions from an entity with ``raw_content``.

Wyświetl plik

@ -1,7 +1,7 @@
import datetime import datetime
import importlib import importlib
import warnings import warnings
from typing import List, Set from typing import List, Set, Union, Dict
from commonmark import commonmark from commonmark import commonmark
@ -16,7 +16,7 @@ class BaseEntity:
_receivers: List = None _receivers: List = None
_source_protocol: str = "" _source_protocol: str = ""
# Contains the original object from payload as a string # Contains the original object from payload as a string
_source_object: str = None _source_object: Union[str, Dict] = None
_sender_key: str = "" _sender_key: str = ""
# ActivityType # ActivityType
activity: ActivityType = None activity: ActivityType = None
@ -50,7 +50,7 @@ class BaseEntity:
klass = getattr(entities, f"{protocol.title()}{self.__class__.__name__}") klass = getattr(entities, f"{protocol.title()}{self.__class__.__name__}")
return klass.from_base(self) return klass.from_base(self)
def extract_mentions(self): def extract_mentions(self) -> Set:
return set() return set()
def validate(self): def validate(self):
@ -178,10 +178,12 @@ class CreatedAtMixin(BaseEntity):
class RawContentMixin(BaseEntity): class RawContentMixin(BaseEntity):
_media_type: str = "text/markdown" _media_type: str = "text/markdown"
_mentions: List = None
_rendered_content: str = "" _rendered_content: str = ""
raw_content: str = "" raw_content: str = ""
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self._mentions = []
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self._required += ["raw_content"] self._required += ["raw_content"]

Wyświetl plik

@ -11,7 +11,7 @@ from federation.tests.fixtures.payloads import (
ACTIVITYPUB_FOLLOW, ACTIVITYPUB_PROFILE, ACTIVITYPUB_PROFILE_INVALID, ACTIVITYPUB_UNDO_FOLLOW, ACTIVITYPUB_POST, ACTIVITYPUB_FOLLOW, ACTIVITYPUB_PROFILE, ACTIVITYPUB_PROFILE_INVALID, ACTIVITYPUB_UNDO_FOLLOW, ACTIVITYPUB_POST,
ACTIVITYPUB_COMMENT, ACTIVITYPUB_RETRACTION, ACTIVITYPUB_SHARE, ACTIVITYPUB_RETRACTION_SHARE, ACTIVITYPUB_COMMENT, ACTIVITYPUB_RETRACTION, ACTIVITYPUB_SHARE, ACTIVITYPUB_RETRACTION_SHARE,
ACTIVITYPUB_POST_IMAGES, ACTIVITYPUB_POST_WITH_SOURCE_MARKDOWN, ACTIVITYPUB_POST_WITH_TAGS, ACTIVITYPUB_POST_IMAGES, ACTIVITYPUB_POST_WITH_SOURCE_MARKDOWN, ACTIVITYPUB_POST_WITH_TAGS,
ACTIVITYPUB_POST_WITH_SOURCE_BBCODE) ACTIVITYPUB_POST_WITH_SOURCE_BBCODE, ACTIVITYPUB_POST_WITH_MENTIONS)
from federation.types import UserType, ReceiverVariant from federation.types import UserType, ReceiverVariant
@ -83,6 +83,15 @@ class TestActivitypubEntityMappersReceive:
assert isinstance(post, Post) assert isinstance(post, Post)
assert post.raw_content == 'boom #test' assert post.raw_content == 'boom #test'
def test_message_to_objects_simple_post__with_mentions(self):
entities = message_to_objects(ACTIVITYPUB_POST_WITH_MENTIONS, "https://mastodon.social/users/jaywink")
assert len(entities) == 1
post = entities[0]
assert isinstance(post, ActivitypubPost)
assert isinstance(post, Post)
assert len(post._mentions) == 1
assert list(post._mentions)[0] == "https://dev3.jasonrobinson.me/u/jaywink/"
def test_message_to_objects_simple_post__with_source__bbcode(self): def test_message_to_objects_simple_post__with_source__bbcode(self):
entities = message_to_objects(ACTIVITYPUB_POST_WITH_SOURCE_BBCODE, "https://diaspodon.fr/users/jaywink") entities = message_to_objects(ACTIVITYPUB_POST_WITH_SOURCE_BBCODE, "https://diaspodon.fr/users/jaywink")
assert len(entities) == 1 assert len(entities) == 1

Wyświetl plik

@ -341,6 +341,50 @@ ACTIVITYPUB_POST_WITH_TAGS = {
'signatureValue': 'SjDACS7Z/Cb1SEC3AtxEokID5SHAYl7kpys/hhmaRbpXuFKCxfj2P9BmH8QhLnuam3sENZlrnBOcB5NlcBhIfwo/Xh242RZBmPQf+edTVYVCe1j19dihcftNCHtnqAcKwp/51dNM/OlKu2730FrwvOUXVIPtB7iVqkseO9TRzDYIDj+zBTksnR/NAYtq6SUpmefXfON0uW3N3Uq6PGfExJaS+aeqRf8cPGkZFSIUQZwOLXbIpb7BFjJ1+y1OMOAJueqvikUprAit3v6BiNWurAvSQpC7WWMFUKyA79/xtkO9kIPA/Q4C9ryqdzxZJ0jDhXiaIIQj2JZfIADdjLZHJA=='} 'signatureValue': 'SjDACS7Z/Cb1SEC3AtxEokID5SHAYl7kpys/hhmaRbpXuFKCxfj2P9BmH8QhLnuam3sENZlrnBOcB5NlcBhIfwo/Xh242RZBmPQf+edTVYVCe1j19dihcftNCHtnqAcKwp/51dNM/OlKu2730FrwvOUXVIPtB7iVqkseO9TRzDYIDj+zBTksnR/NAYtq6SUpmefXfON0uW3N3Uq6PGfExJaS+aeqRf8cPGkZFSIUQZwOLXbIpb7BFjJ1+y1OMOAJueqvikUprAit3v6BiNWurAvSQpC7WWMFUKyA79/xtkO9kIPA/Q4C9ryqdzxZJ0jDhXiaIIQj2JZfIADdjLZHJA=='}
} }
ACTIVITYPUB_POST_WITH_MENTIONS = {'@context': ['https://www.w3.org/ns/activitystreams',
{'ostatus': 'http://ostatus.org#',
'atomUri': 'ostatus:atomUri',
'inReplyToAtomUri': 'ostatus:inReplyToAtomUri',
'conversation': 'ostatus:conversation',
'sensitive': 'as:sensitive'}],
'id': 'https://mastodon.social/users/jaywink/statuses/102750454691863505/activity',
'type': 'Create',
'actor': 'https://mastodon.social/users/jaywink',
'published': '2019-09-07T09:11:54Z',
'to': ['https://www.w3.org/ns/activitystreams#Public'],
'cc': ['https://mastodon.social/users/jaywink/followers',
'https://dev3.jasonrobinson.me/u/jaywink/'],
'object': {'id': 'https://mastodon.social/users/jaywink/statuses/102750454691863505',
'type': 'Note',
'summary': None,
'inReplyTo': None,
'published': '2019-09-07T09:11:54Z',
'url': 'https://mastodon.social/@jaywink/102750454691863505',
'attributedTo': 'https://mastodon.social/users/jaywink',
'to': ['https://www.w3.org/ns/activitystreams#Public'],
'cc': ['https://mastodon.social/users/jaywink/followers',
'https://dev3.jasonrobinson.me/u/jaywink/'],
'sensitive': False,
'atomUri': 'https://mastodon.social/users/jaywink/statuses/102750454691863505',
'inReplyToAtomUri': None,
'conversation': 'tag:mastodon.social,2019-09-07:objectId=123339599:objectType=Conversation',
'content': '<p><span class="h-card"><a href="https://dev3.jasonrobinson.me/u/jaywink/" class="u-url mention">@<span>jaywink</span></a></span> need a mention payload - here!</p>',
'contentMap': {'en': '<p><span class="h-card"><a href="https://dev3.jasonrobinson.me/u/jaywink/" class="u-url mention">@<span>jaywink</span></a></span> need a mention payload - here!</p>'},
'attachment': [],
'tag': [{'type': 'Mention',
'href': 'https://dev3.jasonrobinson.me/u/jaywink/',
'name': '@jaywink@dev3.jasonrobinson.me'}],
'replies': {'id': 'https://mastodon.social/users/jaywink/statuses/102750454691863505/replies',
'type': 'Collection',
'first': {'type': 'CollectionPage',
'next': 'https://mastodon.social/users/jaywink/statuses/102750454691863505/replies?only_other_accounts=true&page=true',
'partOf': 'https://mastodon.social/users/jaywink/statuses/102750454691863505/replies',
'items': []}}},
'signature': {'type': 'RsaSignature2017',
'creator': 'https://mastodon.social/users/jaywink#main-key',
'created': '2019-09-07T09:11:54Z',
'signatureValue': 'FOO'}}
ACTIVITYPUB_POST_WITH_SOURCE_MARKDOWN = { ACTIVITYPUB_POST_WITH_SOURCE_MARKDOWN = {
'@context': ['https://www.w3.org/ns/activitystreams', '@context': ['https://www.w3.org/ns/activitystreams',
{'ostatus': 'http://ostatus.org#', {'ostatus': 'http://ostatus.org#',