kopia lustrzana https://gitlab.com/jaywink/federation
Extract mentions from Diaspora payloads that have text content
The mentions will be available in the entity as `_mentions` which is a set of Diaspora ID's in URI format.merge-requests/130/head
rodzic
8c7b1206c6
commit
af920604a2
|
@ -20,6 +20,8 @@
|
||||||
|
|
||||||
The country information is fetched using the free `ipdata.co` service. NOTE! This service is rate limited to 1500 requests per day.
|
The country information is fetched using the free `ipdata.co` service. NOTE! This service is rate limited to 1500 requests per day.
|
||||||
|
|
||||||
|
* Extract mentions from Diaspora payloads that have text content. The mentions will be available in the entity as `_mentions` which is a set of Diaspora ID's in URI format.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
* Send outbound Diaspora payloads in new format. Remove possibility to generate legacy MagicEnvelope payloads. ([related issue](https://github.com/jaywink/federation/issues/82))
|
* Send outbound Diaspora payloads in new format. Remove possibility to generate legacy MagicEnvelope payloads. ([related issue](https://github.com/jaywink/federation/issues/82))
|
||||||
|
|
|
@ -23,6 +23,7 @@ class BaseEntity:
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self._required = []
|
self._required = []
|
||||||
self._children = []
|
self._children = []
|
||||||
|
self._mentions = set()
|
||||||
for key, value in kwargs.items():
|
for key, value in kwargs.items():
|
||||||
if hasattr(self, key):
|
if hasattr(self, key):
|
||||||
setattr(self, key, value)
|
setattr(self, key, value)
|
||||||
|
@ -31,6 +32,9 @@ class BaseEntity:
|
||||||
self.__class__.__name__, key
|
self.__class__.__name__, key
|
||||||
))
|
))
|
||||||
|
|
||||||
|
def extract_mentions(self):
|
||||||
|
return set()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
"""Global network ID.
|
"""Global network ID.
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import importlib
|
import importlib
|
||||||
|
import re
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
|
@ -8,7 +9,7 @@ from federation.entities.base import (
|
||||||
from federation.entities.diaspora.utils import format_dt, struct_to_xml, get_base_attributes, add_element_to_doc
|
from federation.entities.diaspora.utils import format_dt, struct_to_xml, get_base_attributes, add_element_to_doc
|
||||||
from federation.exceptions import SignatureVerificationError
|
from federation.exceptions import SignatureVerificationError
|
||||||
from federation.protocols.diaspora.signatures import verify_relayable_signature, create_relayable_signature
|
from federation.protocols.diaspora.signatures import verify_relayable_signature, create_relayable_signature
|
||||||
from federation.utils.diaspora import retrieve_and_parse_profile
|
from federation.utils.diaspora import retrieve_and_parse_profile, generate_diaspora_profile_id
|
||||||
|
|
||||||
CLASS_TO_TAG_MAPPING = {
|
CLASS_TO_TAG_MAPPING = {
|
||||||
Comment: "comment",
|
Comment: "comment",
|
||||||
|
@ -27,6 +28,21 @@ 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):
|
||||||
|
"""
|
||||||
|
Extract mentions from an entity with ``raw_content``.
|
||||||
|
|
||||||
|
:return: set
|
||||||
|
"""
|
||||||
|
if not hasattr(self, "raw_content"):
|
||||||
|
return set()
|
||||||
|
mentions = re.findall(r'@{[^;]+; [\w.-]+@[^}]+}', self.raw_content)
|
||||||
|
if not mentions:
|
||||||
|
return set()
|
||||||
|
mentions = {s.split(';')[1].strip(' }') for s in mentions}
|
||||||
|
mentions = {generate_diaspora_profile_id(s) for s in mentions}
|
||||||
|
return mentions
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self):
|
def id(self):
|
||||||
"""Diaspora URI scheme format ID.
|
"""Diaspora URI scheme format ID.
|
||||||
|
|
|
@ -119,6 +119,8 @@ def element_to_objects(element, sender, sender_key_fetcher=None, user=None):
|
||||||
"transformed": transformed,
|
"transformed": transformed,
|
||||||
})
|
})
|
||||||
return []
|
return []
|
||||||
|
# Extract mentions
|
||||||
|
entity._mentions = entity.extract_mentions()
|
||||||
# Do child elements
|
# Do child elements
|
||||||
for child in element:
|
for child in element:
|
||||||
entity._children.extend(element_to_objects(child, sender))
|
entity._children.extend(element_to_objects(child, sender))
|
||||||
|
|
|
@ -110,6 +110,22 @@ class TestEntitiesConvertToXML:
|
||||||
assert etree.tostring(result).decode("utf-8") == converted
|
assert etree.tostring(result).decode("utf-8") == converted
|
||||||
|
|
||||||
|
|
||||||
|
class TestEntitiesExtractMentions:
|
||||||
|
def test_extract_mentions__empty_set_if_no_raw_content(self, diasporacontact):
|
||||||
|
assert diasporacontact.extract_mentions() == set()
|
||||||
|
|
||||||
|
def test_extract_mentions__empty_set_if_no_mentions(self, diasporacomment):
|
||||||
|
assert diasporacomment.extract_mentions() == set()
|
||||||
|
|
||||||
|
def test_extract_mentions__set_contains_mentioned_handles(self, diasporapost):
|
||||||
|
diasporapost.raw_content = 'yeye @{Jason Robinson 🐍🍻; jaywink@jasonrobinson.me} foobar ' \
|
||||||
|
'@{bar; foo@example.com}'
|
||||||
|
assert diasporapost.extract_mentions() == {
|
||||||
|
'diaspora://jaywink@jasonrobinson.me/profile/',
|
||||||
|
'diaspora://foo@example.com/profile/',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class TestEntityAttributes:
|
class TestEntityAttributes:
|
||||||
def test_comment_ids(self, diasporacomment):
|
def test_comment_ids(self, diasporacomment):
|
||||||
assert diasporacomment.id == "diaspora://handle/comment/guid"
|
assert diasporacomment.id == "diaspora://handle/comment/guid"
|
||||||
|
@ -223,7 +239,7 @@ class TestDiasporaRelayableMixin:
|
||||||
b'TsLM+Yw==</parent_author_signature></comment>'
|
b'TsLM+Yw==</parent_author_signature></comment>'
|
||||||
|
|
||||||
@patch("federation.entities.diaspora.mappers.DiasporaComment._validate_signatures")
|
@patch("federation.entities.diaspora.mappers.DiasporaComment._validate_signatures")
|
||||||
def test_sign_with_parent(self, mock_validate):
|
def test_sign_with_parent__calls_to_xml(self, mock_validate):
|
||||||
entity = DiasporaComment()
|
entity = DiasporaComment()
|
||||||
with patch.object(entity, "to_xml") as mock_to_xml:
|
with patch.object(entity, "to_xml") as mock_to_xml:
|
||||||
entity.sign_with_parent(get_dummy_private_key())
|
entity.sign_with_parent(get_dummy_private_key())
|
||||||
|
|
|
@ -17,7 +17,7 @@ from federation.tests.fixtures.payloads import (
|
||||||
DIASPORA_REQUEST, DIASPORA_PROFILE, DIASPORA_POST_INVALID, DIASPORA_RETRACTION,
|
DIASPORA_REQUEST, DIASPORA_PROFILE, DIASPORA_POST_INVALID, DIASPORA_RETRACTION,
|
||||||
DIASPORA_POST_WITH_PHOTOS, DIASPORA_POST_LEGACY_TIMESTAMP, DIASPORA_POST_LEGACY, DIASPORA_CONTACT,
|
DIASPORA_POST_WITH_PHOTOS, DIASPORA_POST_LEGACY_TIMESTAMP, DIASPORA_POST_LEGACY, DIASPORA_CONTACT,
|
||||||
DIASPORA_LEGACY_REQUEST_RETRACTION, DIASPORA_POST_WITH_PHOTOS_2, DIASPORA_PROFILE_EMPTY_TAGS, DIASPORA_RESHARE,
|
DIASPORA_LEGACY_REQUEST_RETRACTION, DIASPORA_POST_WITH_PHOTOS_2, DIASPORA_PROFILE_EMPTY_TAGS, DIASPORA_RESHARE,
|
||||||
DIASPORA_RESHARE_WITH_EXTRA_PROPERTIES, DIASPORA_RESHARE_LEGACY)
|
DIASPORA_RESHARE_WITH_EXTRA_PROPERTIES, DIASPORA_RESHARE_LEGACY, DIASPORA_POST_SIMPLE_WITH_MENTION)
|
||||||
|
|
||||||
|
|
||||||
def mock_fill(attributes):
|
def mock_fill(attributes):
|
||||||
|
@ -26,6 +26,12 @@ def mock_fill(attributes):
|
||||||
|
|
||||||
|
|
||||||
class TestDiasporaEntityMappersReceive:
|
class TestDiasporaEntityMappersReceive:
|
||||||
|
def test_message_to_objects_mentions_are_extracted(self):
|
||||||
|
entities = message_to_objects(DIASPORA_POST_SIMPLE_WITH_MENTION, "alice@alice.diaspora.example.org")
|
||||||
|
assert len(entities) == 1
|
||||||
|
post = entities[0]
|
||||||
|
assert post._mentions == {'diaspora://jaywink@jasonrobinson.me/profile/'}
|
||||||
|
|
||||||
def test_message_to_objects_simple_post(self):
|
def test_message_to_objects_simple_post(self):
|
||||||
entities = message_to_objects(DIASPORA_POST_SIMPLE, "alice@alice.diaspora.example.org")
|
entities = message_to_objects(DIASPORA_POST_SIMPLE, "alice@alice.diaspora.example.org")
|
||||||
assert len(entities) == 1
|
assert len(entities) == 1
|
||||||
|
|
|
@ -73,6 +73,18 @@ DIASPORA_POST_SIMPLE = """
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
DIASPORA_POST_SIMPLE_WITH_MENTION = """
|
||||||
|
<status_message>
|
||||||
|
<text>((status message)) @{Jason Robinson 🐍🍻; jaywink@jasonrobinson.me}</text>
|
||||||
|
<guid>((guidguidguidguidguidguidguid))</guid>
|
||||||
|
<author>alice@alice.diaspora.example.org</author>
|
||||||
|
<public>false</public>
|
||||||
|
<created_at>2011-07-20T01:36:07Z</created_at>
|
||||||
|
<provider_display_name>Socialhome</provider_display_name>
|
||||||
|
</status_message>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
DIASPORA_POST_LEGACY_TIMESTAMP = """
|
DIASPORA_POST_LEGACY_TIMESTAMP = """
|
||||||
<status_message>
|
<status_message>
|
||||||
<text>((status message))</text>
|
<text>((status message))</text>
|
||||||
|
|
Ładowanie…
Reference in New Issue