kopia lustrzana https://github.com/snarfed/bridgy-fed
formalize Protocol.target_for() to take any object, not just actors
important because webmention endpoints are per page (object), not per site (actor).pull/561/head
rodzic
ab1c28ee4d
commit
2a7425a8c6
|
@ -102,11 +102,28 @@ class ActivityPub(User, Protocol):
|
|||
|
||||
@classmethod
|
||||
def target_for(cls, obj, shared=False):
|
||||
"""Returns `obj`'s inbox if it has one, otherwise `None`."""
|
||||
assert obj.source_protocol in (cls.LABEL, cls.ABBREV)
|
||||
"""Returns `obj`'s or its author's/actor's inbox, if available."""
|
||||
assert obj.source_protocol in (cls.LABEL, cls.ABBREV, 'ui', None), str(obj)
|
||||
|
||||
if not obj.as1:
|
||||
return None
|
||||
|
||||
if obj.type not in as1.ACTOR_TYPES:
|
||||
logger.info(f'{obj.key} type {type} is not an actor')
|
||||
for field in 'actor', 'author':
|
||||
inner_obj = as1.get_object(obj.as1, field)
|
||||
inner_id = inner_obj.get('id') or as1.get_url(inner_obj)
|
||||
if not inner_id:
|
||||
continue
|
||||
|
||||
# TODO: need a "soft" kwarg for load to suppress errors?
|
||||
actor = cls.load(inner_id)
|
||||
if actor and actor.as1:
|
||||
target = cls.target_for(actor)
|
||||
if target:
|
||||
logger.info(f'Target for {obj.key} via {inner_id} is {target}')
|
||||
return target
|
||||
|
||||
logger.info(f'{obj.key} type {obj.type} is not an actor and has no author or actor with inbox')
|
||||
|
||||
actor = obj.as_as2()
|
||||
|
||||
|
|
11
protocol.py
11
protocol.py
|
@ -236,10 +236,6 @@ class Protocol:
|
|||
True if the activity is sent successfully, False if it is ignored due
|
||||
to protocol logic. (Failures are raised as exceptions.)
|
||||
|
||||
Returns:
|
||||
True if the activity was sent successfully, False if it was discarded
|
||||
or ignored due to protocol logic, ie not network or other failures
|
||||
|
||||
Raises:
|
||||
:class:`werkzeug.HTTPException` if the request fails
|
||||
"""
|
||||
|
@ -282,7 +278,7 @@ class Protocol:
|
|||
|
||||
@classmethod
|
||||
def target_for(cls, obj, shared=False):
|
||||
"""Returns a recipient :class:`Object`'s delivery target (endpoint).
|
||||
"""Returns an :class:`Object`'s delivery target (endpoint).
|
||||
|
||||
To be implemented by subclasses.
|
||||
|
||||
|
@ -291,7 +287,8 @@ class Protocol:
|
|||
* If obj has `source_protocol` `'web'`, returns its URL, as a
|
||||
webmention target.
|
||||
* If obj is an `'activitypub'` actor, returns its inbox.
|
||||
* If obj is another `'activitypub'` object, returns `None`.
|
||||
* If obj is an `'activitypub'` object, returns it's author's or actor's
|
||||
inbox.
|
||||
|
||||
Args:
|
||||
obj: :class:`Object`
|
||||
|
@ -300,7 +297,7 @@ class Protocol:
|
|||
multiple recipients for efficiency
|
||||
|
||||
Returns:
|
||||
str target endpoint or `None`
|
||||
str target endpoint, or `None` if not available.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
|
|
@ -1784,10 +1784,11 @@ class ActivityPubUtilsTest(TestCase):
|
|||
self.assertEqual('@swentel@mas.to', user.readable_id)
|
||||
self.assertEqual('@swentel@mas.to', user.readable_or_key_id())
|
||||
|
||||
def test_target_for(self):
|
||||
def test_target_for_not_activitypub(self):
|
||||
with self.assertRaises(AssertionError):
|
||||
ActivityPub.target_for(Object(source_protocol='web'))
|
||||
|
||||
def test_target_for_actor(self):
|
||||
self.assertEqual(ACTOR['inbox'], ActivityPub.target_for(
|
||||
Object(source_protocol='ap', as2=ACTOR)))
|
||||
|
||||
|
@ -1810,3 +1811,30 @@ class ActivityPubUtilsTest(TestCase):
|
|||
Object(source_protocol='ap', as2=actor)))
|
||||
self.assertEqual('so-shared', ActivityPub.target_for(
|
||||
Object(source_protocol='ap', as2=actor), shared=True))
|
||||
|
||||
def test_target_for_object(self):
|
||||
obj = Object(as2=NOTE_OBJECT, source_protocol='ap')
|
||||
self.assertIsNone(ActivityPub.target_for(obj))
|
||||
|
||||
Object(id=ACTOR['id'], as2=ACTOR).put()
|
||||
obj.as2 = {
|
||||
**NOTE_OBJECT,
|
||||
'author': ACTOR['id'],
|
||||
}
|
||||
self.assertEqual('http://mas.to/inbox', ActivityPub.target_for(obj))
|
||||
|
||||
del obj.as2['author']
|
||||
obj.as2['actor'] = copy.deepcopy(ACTOR)
|
||||
obj.as2['actor']['url'] = [obj.as2['actor'].pop('id')]
|
||||
self.assertEqual('http://mas.to/inbox', ActivityPub.target_for(obj))
|
||||
|
||||
@patch('requests.get')
|
||||
def test_target_for_object_fetch(self, mock_get):
|
||||
mock_get.return_value = self.as2_resp(ACTOR)
|
||||
|
||||
obj = Object(as2={
|
||||
**NOTE_OBJECT,
|
||||
'author': 'http://the/author',
|
||||
}, source_protocol='ap')
|
||||
self.assertEqual('http://mas.to/inbox', ActivityPub.target_for(obj))
|
||||
mock_get.assert_has_calls([self.as2_req('http://the/author')])
|
||||
|
|
2
web.py
2
web.py
|
@ -253,7 +253,7 @@ class Web(User, Protocol):
|
|||
@classmethod
|
||||
def target_for(cls, obj, shared=False):
|
||||
"""Returns `obj`'s id, as a URL webmention target."""
|
||||
assert obj.source_protocol in (cls.LABEL, cls.ABBREV)
|
||||
assert obj.source_protocol in (cls.LABEL, cls.ABBREV, 'ui', None)
|
||||
|
||||
if not util.is_web(obj.key.id()):
|
||||
logger.warning(f"{obj.key} is source_protocol web but id isn't a URL!")
|
||||
|
|
Ładowanie…
Reference in New Issue