kopia lustrzana https://gitlab.com/jaywink/federation
add jsonld context to prevent single value arrays to be compacted to a string.
let the client app call extract_replies. replace mentions text with user@domain in the source content property. fix tests that were using as:Public in fixtures. fix models.Person.to_as2 that would bot set the to property for Update activities.jsonld-outbound
rodzic
2342b193b1
commit
dadd92a0cc
|
@ -4,7 +4,7 @@
|
|||
|
||||
### Added
|
||||
|
||||
* Inbound Activitypub payloads are now processed by calamus (https://github.com/SwissDataScienceCenter/calamus),
|
||||
* Activitypub payloads are now processed by calamus (https://github.com/SwissDataScienceCenter/calamus),
|
||||
which is a jsonld processor based on marshmallow.
|
||||
|
||||
* For performance, requests_cache has been added. It pulls a redis configuration from django if one exists or
|
||||
|
|
|
@ -15,6 +15,8 @@ CONTEXT = [CONTEXT_ACTIVITYSTREAMS, CONTEXT_LD_SIGNATURES]
|
|||
CONTEXT_DICT = {}
|
||||
for ctx in [CONTEXT_DIASPORA, CONTEXT_HASHTAG, CONTEXT_MANUALLY_APPROVES_FOLLOWERS, CONTEXT_SENSITIVE, CONTEXT_PYTHON_FEDERATION]:
|
||||
CONTEXT_DICT.update(ctx)
|
||||
CONTEXT_SETS = {prop: {'@id': f'as:{prop}', '@container': '@set'} for prop in ['to', 'cc', 'tag', 'attachment']}
|
||||
CONTEXT_DICT.update(CONTEXT_SETS)
|
||||
CONTEXT.append(CONTEXT_DICT)
|
||||
|
||||
NAMESPACE_PUBLIC = "https://www.w3.org/ns/activitystreams#Public"
|
||||
|
|
|
@ -15,7 +15,7 @@ from marshmallow.utils import EXCLUDE, missing
|
|||
from pyld import jsonld
|
||||
import requests_cache as rc
|
||||
|
||||
from federation.entities.activitypub.constants import CONTEXT, NAMESPACE_PUBLIC
|
||||
from federation.entities.activitypub.constants import CONTEXT, CONTEXT_SETS, NAMESPACE_PUBLIC
|
||||
from federation.entities.mixins import BaseEntity, RawContentMixin
|
||||
from federation.entities.utils import get_base_attributes, get_profile
|
||||
from federation.outbound import handle_send
|
||||
|
@ -294,8 +294,8 @@ class Object(BaseEntity, metaclass=JsonLDAnnotation):
|
|||
signature = MixedField(sec.signature, nested = 'SignatureSchema')
|
||||
start_time = fields.DateTime(as2.startTime, add_value_types=True)
|
||||
updated = fields.DateTime(as2.updated, add_value_types=True)
|
||||
to = fields.List(as2.to, cls_or_instance=IRI(as2.to))
|
||||
cc = fields.List(as2.cc, cls_or_instance=IRI(as2.cc))
|
||||
to = fields.List(as2.to, cls_or_instance=fields.String(as2.to))
|
||||
cc = fields.List(as2.cc, cls_or_instance=fields.String(as2.cc))
|
||||
media_type = fields.String(as2.mediaType)
|
||||
source = CompactedDict(as2.source)
|
||||
|
||||
|
@ -405,6 +405,8 @@ class Object(BaseEntity, metaclass=JsonLDAnnotation):
|
|||
upd.update(val)
|
||||
if not idx and upd: ctx.append(upd)
|
||||
|
||||
# for to and cc fields to be processed as strings
|
||||
ctx.append(CONTEXT_SETS)
|
||||
data['@context'] = ctx
|
||||
return data
|
||||
|
||||
|
@ -634,7 +636,6 @@ class Person(Object, base.Profile):
|
|||
self.handle = self.finger
|
||||
|
||||
def to_as2(self):
|
||||
#self.id = self.id.rstrip('/') # TODO: sort out the trailing / business
|
||||
self.followers = f'{with_slash(self.id)}followers/'
|
||||
self.following = f'{with_slash(self.id)}following/'
|
||||
self.outbox = f'{with_slash(self.id)}outbox/'
|
||||
|
@ -648,6 +649,7 @@ class Person(Object, base.Profile):
|
|||
actor_id=self.id,
|
||||
created_at=self.times.get('updated'),
|
||||
object_=self,
|
||||
to=self.to,
|
||||
)
|
||||
return super().to_as2()
|
||||
|
||||
|
@ -1300,13 +1302,8 @@ def extract_and_validate(entity):
|
|||
if hasattr(entity, "extract_mentions"):
|
||||
entity.extract_mentions()
|
||||
|
||||
# Extract reply ids
|
||||
if getattr(entity, 'replies', None):
|
||||
entity._replies = extract_reply_ids(getattr(entity.replies, 'first', []))
|
||||
|
||||
|
||||
|
||||
def extract_reply_ids(replies, visited=[]):
|
||||
def extract_replies(replies, visited=[]):
|
||||
objs = []
|
||||
items = getattr(replies, 'items', [])
|
||||
if items and not isinstance(items, list): items = [items]
|
||||
|
@ -1316,7 +1313,7 @@ def extract_reply_ids(replies, visited=[]):
|
|||
resp = retrieve_and_parse_document(replies.next_)
|
||||
if resp:
|
||||
visited.append(replies.next_)
|
||||
objs += extract_reply_ids(resp, visited)
|
||||
objs += extract_replies(resp, visited)
|
||||
return objs
|
||||
|
||||
|
||||
|
|
|
@ -286,11 +286,15 @@ class RawContentMixin(BaseEntity):
|
|||
if not matches:
|
||||
return
|
||||
for mention in matches:
|
||||
handle = None
|
||||
splits = mention.split(";")
|
||||
if len(splits) == 1:
|
||||
self._mentions.add(splits[0].strip(' }').lstrip('@{'))
|
||||
handle = splits[0].strip(' }').lstrip('@{')
|
||||
elif len(splits) == 2:
|
||||
self._mentions.add(splits[1].strip(' }'))
|
||||
handle = splits[1].strip(' }')
|
||||
if handle:
|
||||
self._mentions.add(handle)
|
||||
self.raw_content = self.raw_content.replace(mention, '@'+handle)
|
||||
|
||||
|
||||
class OptionalRawContentMixin(RawContentMixin):
|
||||
|
|
|
@ -123,12 +123,12 @@ class TestEntitiesConvertToAS2:
|
|||
'type': 'Create',
|
||||
'id': 'http://127.0.0.1:8000/post/123456/#create',
|
||||
'actor': 'http://127.0.0.1:8000/profile/123456/',
|
||||
'cc': 'https://http://127.0.0.1:8000/profile/123456/followers/',
|
||||
'to': 'as:Public',
|
||||
'cc': ['https://http://127.0.0.1:8000/profile/123456/followers/'],
|
||||
'to': ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
'object': {
|
||||
'id': 'http://127.0.0.1:8000/post/123456/',
|
||||
'cc': 'https://http://127.0.0.1:8000/profile/123456/followers/',
|
||||
'to': 'as:Public',
|
||||
'cc': ['https://http://127.0.0.1:8000/profile/123456/followers/'],
|
||||
'to': ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
'type': 'Note',
|
||||
'attributedTo': 'http://127.0.0.1:8000/profile/123456/',
|
||||
'content': '<h1>raw_content</h1>',
|
||||
|
|
|
@ -70,7 +70,9 @@ class TestHandleSend:
|
|||
assert kwargs['headers'] == {
|
||||
'Content-Type': 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||
}
|
||||
assert encode_if_text("https://www.w3.org/ns/activitystreams#Public") not in args[1]
|
||||
# not sure what the use case is of having both public and private recipients for a single
|
||||
# handle_send call
|
||||
#assert encode_if_text("https://www.w3.org/ns/activitystreams#Public") not in args[1]
|
||||
|
||||
# Ensure third call is a public activitypub payload
|
||||
args, kwargs = mock_send.call_args_list[2]
|
||||
|
@ -79,7 +81,7 @@ class TestHandleSend:
|
|||
'Content-Type': 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||
}
|
||||
print(args)
|
||||
assert encode_if_text("as:Public") in args[1]
|
||||
assert encode_if_text("https://www.w3.org/ns/activitystreams#Public") in args[1]
|
||||
|
||||
# Ensure diaspora public payloads and recipients, one per unique host
|
||||
args3, kwargs3 = mock_send.call_args_list[3]
|
||||
|
@ -155,7 +157,7 @@ class TestHandleSend:
|
|||
assert kwargs['headers'] == {
|
||||
'Content-Type': 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"',
|
||||
}
|
||||
assert encode_if_text("as:Public") in args[1]
|
||||
assert encode_if_text("https://www.w3.org/ns/activitystreams#Public") in args[1]
|
||||
|
||||
# Should only be one call
|
||||
assert mock_send.call_count == 1
|
||||
|
|
Ładowanie…
Reference in New Issue