Object.as1: inject actor/author when converting from bsky objects

...since they imply actor/author in the AT URI's repo DID.
pull/642/head
Ryan Barrett 2023-09-18 11:19:55 -07:00
rodzic 35ded3514d
commit a723be660e
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
2 zmienionych plików z 62 dodań i 4 usunięć

Wyświetl plik

@ -28,7 +28,7 @@ from common import add, base64_to_long, long_to_base64, redirect_unwrap
# maps string label to Protocol subclass. populated by ProtocolUserMeta.
# seed with old and upcoming protocols that don't have their own classes (yet).
PROTOCOLS = {'atproto': None, 'bluesky': None, 'ostatus': None}
PROTOCOLS = {'ostatus': None}
# 2048 bits makes tests slow, so use 1024 for them
KEY_BITS = 1024 if DEBUG else 2048
@ -43,7 +43,7 @@ OBJECT_EXPIRE_TYPES = (
'accept',
'reject',
'undo',
None
None,
)
OBJECT_EXPIRE_AGE = timedelta(days=90)
@ -54,10 +54,12 @@ class ProtocolUserMeta(type(ndb.Model)):
""":class:`User` metaclass. Registers all subclasses in the PROTOCOLS global."""
def __new__(meta, name, bases, class_dict):
cls = super().__new__(meta, name, bases, class_dict)
if hasattr(cls, 'LABEL') and cls.LABEL not in ('protocol', 'user'):
for label in (cls.LABEL, cls.ABBREV) + cls.OTHER_LABELS:
if label:
PROTOCOLS[label] = cls
return cls
@ -474,10 +476,26 @@ class Object(StringIdModel):
if self.our_as1:
obj = redirect_unwrap(self.our_as1)
elif self.as2:
obj = as2.to_as1(redirect_unwrap(self.as2))
elif self.bsky:
obj = bluesky.to_as1(self.bsky)
# ATProto implies actor from repo; fill that in here
type = obj.get('objectType')
field = ('actor' if type == 'activity'
else 'author' if type not in as1.ACTOR_TYPES
else None)
if field:
repo, _, _ = arroba.util.parse_at_uri(self.key.id())
user = User.get_by_atproto_did(repo)
if user:
logger.debug(f'Filling in {field} from {user}')
user_as1 = (user.obj.as1 if user.obj and user.obj.as1
else user.key.id())
obj.setdefault(field, user_as1)
elif self.mf2:
obj = microformats2.json_to_object(self.mf2,
rel_urls=self.mf2.get('rel-urls'))
@ -487,6 +505,7 @@ class Object(StringIdModel):
for field in 'author', 'actor', 'object': # None is obj itself
if url := util.get_url(obj, field):
as1.get_object(obj, field).setdefault('id', url)
else:
return None
@ -508,7 +527,7 @@ class Object(StringIdModel):
def _expire(self):
"""Maybe automatically delete this Object after 90d using a TTL policy.
https://cloud.google.com/datastore/docs/ttl#ttl_properties_and_indexes
https://cloud.google.com/datastore/docs/ttl
They recommend not indexing TTL properties:
https://cloud.google.com/datastore/docs/ttl#ttl_properties_and_indexes

Wyświetl plik

@ -401,7 +401,7 @@ class ObjectTest(TestCase):
obj.as2 = {'baz': 'biff'}
self.assertEqual({'baz': 'biff'}, obj.as_as2())
def test_as1(self):
def test_as1_from_as2(self):
self.assert_equals({
'objectType': 'person',
'id': 'https://mas.to/users/swentel',
@ -414,6 +414,45 @@ class ObjectTest(TestCase):
self.assertEqual({'id': 'x', 'foo': 'bar'},
Object(id='x', our_as1={'foo': 'bar'}).as1)
def test_as1_from_bsky(self):
like_bsky = {
'$type': 'app.bsky.feed.like',
'subject': {
'uri': 'http://example.com/original/post',
'cid': 'TODO',
},
}
like_as1 = {
'objectType': 'activity',
'verb': 'like',
'id': 'at://did:plc:foo/co.ll/123',
'object': 'http://example.com/original/post',
}
# no user
obj = Object(id='at://did:plc:foo/co.ll/123', bsky=like_bsky)
self.assert_equals(like_as1, obj.as1)
# user without Object
user = self.make_user(id='fake:user', cls=Fake, atproto_did=f'did:plc:foo')
obj = Object(id='at://did:plc:foo/co.ll/123', bsky=like_bsky)
self.assertEqual({
**like_as1,
'actor': 'fake:user',
}, obj.as1)
# user with Object
user.obj = self.store_object(id='fake:profile', our_as1={'foo': 'bar'})
user.put()
obj = Object(id='at://did:plc:foo/co.ll/123', bsky=like_bsky)
self.assertEqual({
**like_as1,
'actor': {
'id': 'fake:profile',
'foo': 'bar',
},
}, obj.as1)
def test_as1_from_mf2_uses_url_as_id(self):
obj = Object(mf2={
'properties': {