atproto: handle bsky.app URLs in load, not fetch

pull/923/head
Ryan Barrett 2024-03-14 15:40:25 -07:00
rodzic 9b2bb9ef37
commit 878bbde328
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
3 zmienionych plików z 71 dodań i 38 usunięć

Wyświetl plik

@ -362,15 +362,22 @@ class ATProto(User, Protocol):
@classmethod
def load(cls, id, did_doc=False, **kwargs):
"""Thin wrapper that converts DIDs to profile URIs.
"""Thin wrapper that converts DIDs and bsky.app URLs to at:// URIs.
Args:
did_doc (bool): if True, loads and returns a DID document object
instead of an ``app.bsky.actor.profile/self``.
"""
if not did_doc and id.startswith('did:'):
if id.startswith('did:') and not did_doc:
id = cls.profile_at_uri(id)
elif id.startswith('https://bsky.app/'):
try:
id = bluesky.web_url_to_at_uri(id)
except ValueError as e:
logger.warning(f"Couldn't convert {id} to at:// URI: {e}")
return None
return super().load(id, **kwargs)
@classmethod
@ -394,6 +401,8 @@ class ATProto(User, Protocol):
logger.info(f"ATProto can't fetch {id}")
return False
assert not id.startswith('https://bsky.app/') # handled in load
# did:plc, did:web
if id.startswith('did:'):
try:
@ -403,15 +412,6 @@ class ATProto(User, Protocol):
util.interpret_http_exception(e)
return False
if id.startswith('https://bsky.app/'):
try:
id = bluesky.web_url_to_at_uri(id)
except ValueError:
return False
if not id:
return False
obj.key = ndb.Key(Object, id)
# at:// URI. if it has a handle, resolve and replace with DID.
# examples:
# at://did:plc:s2koow7r6t7tozgd4slc3dsg/app.bsky.feed.post/3jqcpv7bv2c2q

Wyświetl plik

@ -1112,6 +1112,7 @@ class Protocol:
Raises:
requests.HTTPError: anything that :meth:`fetch` raises
"""
assert id
assert local or remote is not False
# logger.debug(f'Loading Object {id} local={local} remote={remote}')

Wyświetl plik

@ -283,37 +283,16 @@ class ATProtoTest(TestCase):
'https://api.bsky-sandbox.dev/xrpc/com.atproto.repo.getRecord?repo=did%3Aplc%3Aabc&collection=app.bsky.feed.post&rkey=123',
json=None, data=None, headers=ANY)
@patch('dns.resolver.resolve', side_effect=dns.resolver.NXDOMAIN())
@patch('requests.get', side_effect=[
# resolving handle, HTTPS method
requests_response('did:plc:abc', content_type='text/plain'),
# AppView getRecord
requests_response({
'cid': 'bafy...',
'value': {'foo': 'bar'},
}),
])
def test_fetch_bsky_app_url(self, mock_get, _):
obj = Object(id='https://bsky.app/profile/han.dull/post/789')
self.assertTrue(ATProto.fetch(obj))
self.assertEqual('at://did:plc:abc/app.bsky.feed.post/789', obj.key.id())
self.assertEqual({
'foo': 'bar',
'cid': 'bafy...',
}, obj.bsky)
mock_get.assert_called_with(
'https://api.bsky-sandbox.dev/xrpc/com.atproto.repo.getRecord?repo=did%3Aplc%3Aabc&collection=app.bsky.feed.post&rkey=789',
json=None, data=None, headers={
'Content-Type': 'application/json',
'User-Agent': common.USER_AGENT,
},
)
def test_fetch_bsky_app_url_fails(self):
for uri in ('https://bsky.app/profile/han.dull',
'https://bsky.app/profile/han.dull/post/789'):
with self.assertRaises(AssertionError):
ATProto.fetch(Object(id=uri))
@patch('dns.resolver.resolve', side_effect=dns.resolver.NXDOMAIN())
@patch('requests.get', return_value=requests_response(status=404))
def test_fetch_resolve_handle_fails(self, mock_get, _):
obj = Object(id='https://bsky.app/profile/bad.com/post/789')
obj = Object(id='at://bad.com/app.bsky.feed.post/789')
self.assertFalse(ATProto.fetch(obj))
def test_load_did_doc(self):
@ -326,6 +305,59 @@ class ATProtoTest(TestCase):
bsky=ACTOR_PROFILE_BSKY)
self.assert_entities_equal(profile, ATProto.load('did:plc:user'))
@patch('dns.resolver.resolve', side_effect=dns.resolver.NXDOMAIN())
@patch('requests.get', side_effect=[
# resolving handle, HTTPS method
requests_response('did:plc:user', content_type='text/plain'),
# AppView getRecord
requests_response({
'cid': 'bafy...',
'value': {'$type': 'app.bsky.actor.profile', 'bar': 'baz'},
}),
# fetching DID doc
requests_response(DID_DOC),
])
def test_load_bsky_app_post_url(self, mock_get, _):
obj = ATProto.load('https://bsky.app/profile/han.dull/post/789')
self.assertEqual('at://did:plc:user/app.bsky.feed.post/789', obj.key.id())
self.assertEqual({
'$type': 'app.bsky.actor.profile',
'bar': 'baz',
'cid': 'bafy...',
}, obj.bsky)
mock_get.assert_any_call(
'https://api.bsky-sandbox.dev/xrpc/com.atproto.repo.getRecord?repo=did%3Aplc%3Auser&collection=app.bsky.feed.post&rkey=789',
json=None, data=None, headers={
'Content-Type': 'application/json',
'User-Agent': common.USER_AGENT,
})
self.assert_req(mock_get, 'https://plc.local/did:plc:user')
@patch('requests.get', return_value=requests_response({
'cid': 'bafy...',
'value': {'$type': 'app.bsky.actor.profile', 'bar': 'baz'},
}))
def test_load_bsky_profile_url(self, mock_get):
self.store_object(id='did:plc:user', raw=DID_DOC)
self.make_user('did:plc:user', cls=ATProto)
obj = ATProto.load('https://bsky.app/profile/han.dull')
self.assertEqual('at://did:plc:user/app.bsky.actor.profile/self', obj.key.id())
self.assertEqual({
'$type': 'app.bsky.actor.profile',
'bar': 'baz',
'cid': 'bafy...',
}, obj.bsky)
mock_get.assert_called_with(
'https://api.bsky-sandbox.dev/xrpc/com.atproto.repo.getRecord?repo=did%3Aplc%3Auser&collection=app.bsky.actor.profile&rkey=self',
json=None, data=None, headers={
'Content-Type': 'application/json',
'User-Agent': common.USER_AGENT,
},
)
def test_convert_bsky_pass_through(self):
self.assertEqual({
'foo': 'bar',