Merge branch 'root_target' into 'master'

Add support for root parent for Comment entity

See merge request jaywink/federation!149
merge-requests/150/head
Jason Robinson 2019-07-15 14:16:53 +00:00
commit 761ae5c5de
9 zmienionych plików z 87 dodań i 9 usunięć

Wyświetl plik

@ -22,6 +22,10 @@
ActivityPub profiles will parse these values from incoming profile documents. Diaspora entities will default to the inboxes in the specification.
* Added support for Diaspora `Comment` entity `thread_parent_guid` attribute.
* Added `root_target_id` and `root_target_guid` to `Comment` base entity. This allows referring to a parent object up the hierarchy chain for threaded comments.
### Changed
* **Backwards incompatible.** Lowest compatible Python version is now 3.6.

Wyświetl plik

@ -5,7 +5,7 @@ from dirty_validators.basic import Email
from federation.entities.activitypub.enums import ActivityType
from federation.entities.mixins import (
PublicMixin, TargetIDMixin, ParticipationMixin, CreatedAtMixin, RawContentMixin, OptionalRawContentMixin,
EntityTypeMixin, ProviderDisplayNameMixin)
EntityTypeMixin, ProviderDisplayNameMixin, RootTargetIDMixin)
class Accept(CreatedAtMixin, TargetIDMixin):
@ -34,7 +34,7 @@ class Image(PublicMixin, OptionalRawContentMixin, CreatedAtMixin):
self._required += ["remote_path", "remote_name"]
class Comment(RawContentMixin, ParticipationMixin, CreatedAtMixin):
class Comment(RawContentMixin, ParticipationMixin, CreatedAtMixin, RootTargetIDMixin):
"""Represents a comment, linked to another object."""
participation = "comment"
url = ""

Wyświetl plik

@ -15,7 +15,8 @@ class DiasporaComment(DiasporaRelayableMixin, Comment):
element = etree.Element(self._tag_name)
struct_to_xml(element, [
{"guid": self.guid},
{"parent_guid": self.target_guid},
{"parent_guid": self.root_target_guid or self.target_guid},
{"thread_parent_guid": self.target_guid},
{"author_signature": self.signature},
{"parent_author_signature": self.parent_signature},
{"text": self.raw_content},

Wyświetl plik

@ -188,6 +188,9 @@ def transform_attributes(attrs, cls):
elif key in ("target_guid", "root_guid", "parent_guid"):
transformed["target_id"] = value
transformed["target_guid"] = value
elif key == "thread_parent_guid":
transformed["root_target_id"] = value
transformed["root_target_guid"] = value
elif key in ("first_name", "last_name"):
values = [attrs.get('first_name'), attrs.get('last_name')]
values = [v for v in values if v]

Wyświetl plik

@ -137,6 +137,12 @@ class TargetIDMixin(BaseEntity):
self._required += ["target_id"]
class RootTargetIDMixin(BaseEntity):
root_target_id = ""
root_target_handle = ""
root_target_guid = ""
class ParticipationMixin(TargetIDMixin):
"""Reflects a participation to something."""
participation = ""

Wyświetl plik

@ -27,6 +27,19 @@ class TestEntitiesConvertToXML:
assert len(result.find("created_at").text) > 0
result.find("created_at").text = "" # timestamp makes testing painful
converted = b"<comment><guid>guid</guid><parent_guid>target_guid</parent_guid>" \
b"<thread_parent_guid>target_guid</thread_parent_guid>" \
b"<author_signature>signature</author_signature><parent_author_signature>" \
b"</parent_author_signature><text>raw_content</text><author>alice@example.com</author>" \
b"<created_at></created_at></comment>"
assert etree.tostring(result) == converted
def test_nested_comment_to_xml(self, diasporanestedcomment):
result = diasporanestedcomment.to_xml()
assert result.tag == "comment"
assert len(result.find("created_at").text) > 0
result.find("created_at").text = "" # timestamp makes testing painful
converted = b"<comment><guid>guid</guid><parent_guid>target_guid</parent_guid>" \
b"<thread_parent_guid>thread_target_guid</thread_parent_guid>" \
b"<author_signature>signature</author_signature><parent_author_signature>" \
b"</parent_author_signature><text>raw_content</text><author>alice@example.com</author>" \
b"<created_at></created_at></comment>"
@ -122,13 +135,15 @@ class TestDiasporaRelayableMixin:
guid="guid",
target_id="target_guid",
target_guid="target_guid",
root_target_id="target_guid",
root_target_guid="target_guid",
)
entity.sign(get_dummy_private_key())
assert entity.signature == "OWvW/Yxw4uCnx0WDn0n5/B4uhyZ8Pr6h3FZaw8J7PCXyPluOfYXFoHO21bykP8c2aVnuJNHe+lmeAkUC" \
"/kHnl4yxk/jqe3uroW842OWvsyDRQ11vHxhIqNMjiepFPkZmXX3vqrYYh5FrC/tUsZrEc8hHoOIHXFR2" \
"kGD0gPV+4EEG6pbMNNZ+SBVun0hvruX8iKQVnBdc/+zUI9+T/MZmLyqTq/CvuPxDyHzQPSHi68N9rJyr" \
"4Xa1K+R33Xq8eHHxs8LVNRqzaHGeD3DX8yBu/vP9TYmZsiWlymbuGwLCa4Yfv/VS1hQZovhg6YTxV4CR" \
"v4ToGL+CAJ7UHEugRRBwDw=="
assert entity.signature == "XZYggFdQHOicguZ0ReVJkYiK5othHgBgAtwnSmm4NR31qeLa76Ur/i2B5Xi9dtopDlNS8EbFy+MLJ1ds" \
"ovDjPsVC1nLZrL57y0v+HtwJas6hQqNbvmEyr1q6X+0p1i93eINzt/7bxcP5uEGxy8J4ItsJzbDVLlC5" \
"3ZtIg7pmhR0ltqNqBHrgL8WDokfGKFlXqANchbD+Xeyv2COGbI78LwplVdYjHW1+jefjpYhMCxayIvMv" \
"WS8TV1hMTqUz+zSqoCHU04RgjjGW8e8vINDblQwMfEMeJ5T6OP5RiU3zCqDc3uL2zxHHh9IGC+clVuhP" \
"HTv8tHUHNLgc2vIzRtGh6w=="
def test_signing_like_works(self):
entity = DiasporaLike(

Wyświetl plik

@ -18,7 +18,7 @@ from federation.tests.fixtures.payloads import (
DIASPORA_POST_WITH_PHOTOS, DIASPORA_CONTACT,
DIASPORA_PROFILE_EMPTY_TAGS, DIASPORA_RESHARE,
DIASPORA_RESHARE_WITH_EXTRA_PROPERTIES, DIASPORA_POST_SIMPLE_WITH_MENTION,
DIASPORA_PROFILE_FIRST_NAME_ONLY)
DIASPORA_PROFILE_FIRST_NAME_ONLY, DIASPORA_POST_COMMENT_NESTED)
class TestDiasporaEntityMappersReceive:
@ -71,6 +71,7 @@ class TestDiasporaEntityMappersReceive:
assert isinstance(comment, DiasporaComment)
assert isinstance(comment, Comment)
assert comment.target_guid == "((parent_guidparent_guidparent_guidparent_guid))"
assert comment.root_target_guid == ""
assert comment.guid == "((guidguidguidguidguidguid))"
assert comment.handle == "alice@alice.diaspora.example.org"
assert comment.participation == "comment"
@ -81,6 +82,26 @@ class TestDiasporaEntityMappersReceive:
]
mock_validate.assert_called_once_with()
@patch("federation.entities.diaspora.mappers.DiasporaComment._validate_signatures")
def test_message_to_objects_nested_comment(self, mock_validate):
entities = message_to_objects(DIASPORA_POST_COMMENT_NESTED, "alice@alice.diaspora.example.org",
sender_key_fetcher=Mock())
assert len(entities) == 1
comment = entities[0]
assert isinstance(comment, DiasporaComment)
assert isinstance(comment, Comment)
assert comment.target_guid == "((parent_guidparent_guidparent_guidparent_guid))"
assert comment.root_target_guid == "((threadparentguid))"
assert comment.guid == "((guidguidguidguidguidguid))"
assert comment.handle == "alice@alice.diaspora.example.org"
assert comment.participation == "comment"
assert comment.raw_content == "((text))"
assert comment.signature == "((signature))"
assert comment._xml_tags == [
"guid", "parent_guid", "thread_parent_guid", "text", "author",
]
mock_validate.assert_called_once_with()
@patch("federation.entities.diaspora.mappers.DiasporaLike._validate_signatures")
def test_message_to_objects_like(self, mock_validate):
entities = message_to_objects(

Wyświetl plik

@ -118,6 +118,22 @@ def diasporacomment():
)
@pytest.fixture
def diasporanestedcomment():
return DiasporaComment(
raw_content="raw_content",
signature="signature",
id="guid",
guid="guid",
actor_id="alice@example.com",
handle="alice@example.com",
target_id="thread_target_guid",
target_guid="thread_target_guid",
root_target_id="target_guid",
root_target_guid="target_guid",
)
@pytest.fixture
def diasporacontact():
return DiasporaContact(

Wyświetl plik

@ -91,6 +91,18 @@ DIASPORA_POST_COMMENT = """
</comment>
"""
DIASPORA_POST_COMMENT_NESTED = """
<comment>
<guid>((guidguidguidguidguidguid))</guid>
<parent_guid>((parent_guidparent_guidparent_guidparent_guid))</parent_guid>
<thread_parent_guid>((threadparentguid))</thread_parent_guid>
<author_signature>((base64-encoded data))</author_signature>
<text>((text))</text>
<author>alice@alice.diaspora.example.org</author>
<author_signature>((signature))</author_signature>
</comment>
"""
DIASPORA_POST_LIKE = """
<like>
<parent_type>Post</parent_type>