diff --git a/atproto.py b/atproto.py index e4ff0e5..8d1c4e1 100644 --- a/atproto.py +++ b/atproto.py @@ -96,6 +96,7 @@ class ATProto(User, Protocol): # need to update serviceEndpoint in all users' DID docs. :/ PDS_URL = f'https://atproto{common.SUPERDOMAIN}/' CONTENT_TYPE = 'application/json' + HAS_COPIES = True DEFAULT_ENABLED_PROTOCOLS = () def _pre_put_hook(self): diff --git a/ids.py b/ids.py index dd9b7b3..1b50a1a 100644 --- a/ids.py +++ b/ids.py @@ -23,8 +23,8 @@ import models logger = logging.getLogger(__name__) # Protocols to check User.copies and Object.copies before translating -# TODO: move to Protocol -COPIES_PROTOCOLS = ('atproto',) +# populated in models.reset_protocol_properties +COPIES_PROTOCOLS = None # Web user domains whose AP actor ids are on fed.brid.gy, not web.brid.gy, for # historical compatibility. Loaded on first call to web_ap_subdomain(). diff --git a/models.py b/models.py index c044a48..6c10c87 100644 --- a/models.py +++ b/models.py @@ -120,6 +120,8 @@ def reset_protocol_properties(): abbrevs = f'({"|".join(PROTOCOLS.keys())}|fed)' common.SUBDOMAIN_BASE_URL_RE = re.compile( rf'^https?://({abbrevs}\.brid\.gy|localhost(:8080)?)/(convert/|r/)?({abbrevs}/)?(?P.+)') + ids.COPIES_PROTOCOLS = tuple(label for label, proto in PROTOCOLS.items() + if proto and proto.HAS_COPIES) class User(StringIdModel, metaclass=ProtocolUserMeta): @@ -360,6 +362,7 @@ class User(StringIdModel, metaclass=ProtocolUserMeta): Args: to_proto (:class:`protocol.Protocol` subclass) """ + logger.info(f'Enabling {to_proto.LABEL} for {self.key}') user = self.key.get() add(user.enabled_protocols, to_proto.LABEL) if to_proto.LABEL in ids.COPIES_PROTOCOLS and not user.get_copy(to_proto): @@ -375,6 +378,7 @@ class User(StringIdModel, metaclass=ProtocolUserMeta): Args: to_proto (:class:`protocol.Protocol` subclass) """ + logger.info(f'Disabling {to_proto.LABEL} for {self.key}') user = self.key.get() remove(user.enabled_protocols, to_proto.LABEL) # TODO: delete copy user diff --git a/protocol.py b/protocol.py index ca4957e..094e351 100644 --- a/protocol.py +++ b/protocol.py @@ -80,6 +80,9 @@ class Protocol: appropriate for the ``Content-Type`` HTTP header. HAS_FOLLOW_ACCEPTS (bool): whether this protocol supports explicit accept/reject activities in response to follows, eg ActivityPub + HAS_COPIES (bool): whether this protocol is push and needs us to + proactively create "copy" users and objects, as opposed to pulling + converted objects on demand DEFAULT_ENABLED_PROTOCOLS (list of str): labels of other protocols that are automatically enabled for this protocol to bridge into """ @@ -89,6 +92,7 @@ class Protocol: LOGO_HTML = '' CONTENT_TYPE = None HAS_FOLLOW_ACCEPTS = False + HAS_COPIES = False DEFAULT_ENABLED_PROTOCOLS = () def __init__(self): diff --git a/tests/testutil.py b/tests/testutil.py index dabefb3..70aae02 100644 --- a/tests/testutil.py +++ b/tests/testutil.py @@ -70,6 +70,7 @@ class Fake(User, protocol.Protocol): ABBREV = 'fa' PHRASE = 'fake-phrase' CONTENT_TYPE = 'fa/ke' + HAS_COPIES = True # maps string ids to dict AS1 objects that can be fetched fetchable = {} @@ -231,7 +232,6 @@ class TestCase(unittest.TestCase, testutil.Asserts): cls.created_for = [] ids._NON_WEB_SUBDOMAIN_SITES = None - ids.COPIES_PROTOCOLS = ('atproto', 'fake', 'other', 'eefake') # make random test data deterministic arroba.util._clockid = 17