diff --git a/atproto.py b/atproto.py index 3f4477c..e4ff0e5 100644 --- a/atproto.py +++ b/atproto.py @@ -567,7 +567,7 @@ def poll_notifications(): repos = {r.key.id(): r for r in AtpRepo.query()} logger.info(f'Got {len(repos)} repos') if not repos: - return + return 'Nothing to do ¯\_(ツ)_/¯', 204 users = itertools.chain(*(cls.query(cls.copies.uri.IN(list(repos))) for cls in set(PROTOCOLS.values()) @@ -626,7 +626,7 @@ def poll_posts(): repos = {r.key.id(): r for r in AtpRepo.query()} logger.info(f'Got {len(repos)} repos') if not repos: - return + return 'Nothing to do ¯\_(ツ)_/¯', 204 users = itertools.chain(*(cls.query(cls.copies.uri.IN(list(repos))) for cls in set(PROTOCOLS.values()) diff --git a/ids.py b/ids.py index 69715b2..dd9b7b3 100644 --- a/ids.py +++ b/ids.py @@ -23,6 +23,7 @@ import models logger = logging.getLogger(__name__) # Protocols to check User.copies and Object.copies before translating +# TODO: move to Protocol COPIES_PROTOCOLS = ('atproto',) # Web user domains whose AP actor ids are on fed.brid.gy, not web.brid.gy, for diff --git a/models.py b/models.py index 7d5ebc4..c044a48 100644 --- a/models.py +++ b/models.py @@ -362,7 +362,7 @@ class User(StringIdModel, metaclass=ProtocolUserMeta): """ user = self.key.get() add(user.enabled_protocols, to_proto.LABEL) - if not user.get_copy(to_proto): + if to_proto.LABEL in ids.COPIES_PROTOCOLS and not user.get_copy(to_proto): to_proto.create_for(user) user.put() diff --git a/tests/test_integrations.py b/tests/test_integrations.py index e30143c..b0ee594 100644 --- a/tests/test_integrations.py +++ b/tests/test_integrations.py @@ -361,8 +361,7 @@ class IntegrationTests(TestCase): @patch('requests.post', return_value=requests_response('OK')) # create DID @patch('requests.get') - def test_activitypub_follow_bsky_bot_user_enables_protocol( - self, mock_get, mock_post): + def test_activitypub_follow_bsky_bot_user_enables_protocol(self, mock_get, _): """AP follow of @bsky.brid.gy@bsky.brid.gy bridges the account into BLuesky. ActivityPub user @alice@inst , https://inst/alice @@ -376,7 +375,7 @@ class IntegrationTests(TestCase): 'preferredUsername': 'alice', 'inbox': 'http://inst/inbox', }) - bot_user = self.make_user(id='bsky.brid.gy', cls=Web, ap_subdomain='bsky') + self.make_user(id='bsky.brid.gy', cls=Web, ap_subdomain='bsky') # deliver follow resp = self.post('/bsky.brid.gy/inbox', json={ @@ -402,3 +401,57 @@ class IntegrationTests(TestCase): records = repo.get_contents() self.assertEqual(['app.bsky.actor.profile'], list(records.keys())) self.assertEqual(['self'], list(records['app.bsky.actor.profile'].keys())) + + + @patch('requests.post') + @patch('requests.get') + def test_atproto_follow_ap_bot_user_enables_protocol(self, mock_get, mock_post): + """Bluesky follow of @ap.brid.gy enables the ActivityPub protocol. + + ATProto user alice.com, did:plc:alice + ActivityPub bot user @ap.brid.gy, did:plc:ap + """ + self.make_user(id='ap.brid.gy', cls=Web, ap_subdomain='ap', + enabled_protocols=['atproto'], + copies=[Target(uri='did:plc:ap', protocol='atproto')]) + self.store_object(id='did:plc:ap', raw={ + **DID_DOC, + 'id': 'did:plc:ap', + 'alsoKnownAs': ['at://ap.brid.gy'], + }) + storage = DatastoreStorage() + Repo.create(storage, 'did:plc:ap', signing_key=ATPROTO_KEY) + + mock_get.side_effect = [ + # ATProto listNotifications + requests_response({ + 'cursor': '...', + 'notifications': [{ + 'uri': 'at://did:plc:alice/app.bsky.graph.follow/456', + 'cid': '...', + 'author': { + '$type': 'app.bsky.actor.defs#profileView', + 'did': 'did:plc:alice', + 'handle': 'alice.com', + }, + 'reason': 'follow', + 'record': { + '$type': 'app.bsky.graph.follow', + 'subject': 'did:plc:ap', + }, + }], + }), + # alice DID + requests_response(DID_DOC), + # alice profile + requests_response(PROFILE_GETRECORD), + # alice.com handle resolution, HTTPS method + # requests_response('did:plc:alice', content_type='text/plain'), + # # alice profile + # requests_response(PROFILE_GETRECORD), + ] + resp = self.post('/queue/atproto-poll-notifs', client=hub.app.test_client()) + self.assertEqual(200, resp.status_code) + + user = ATProto.get_by_id('did:plc:alice') + self.assertTrue(ATProto.is_enabled_to(ActivityPub, user=user)) diff --git a/tests/testutil.py b/tests/testutil.py index 5a59013..dabefb3 100644 --- a/tests/testutil.py +++ b/tests/testutil.py @@ -231,7 +231,7 @@ class TestCase(unittest.TestCase, testutil.Asserts): cls.created_for = [] ids._NON_WEB_SUBDOMAIN_SITES = None - ids.COPIES_PROTOCOLS = ('atproto', 'fake', 'other') + ids.COPIES_PROTOCOLS = ('atproto', 'fake', 'other', 'eefake') # make random test data deterministic arroba.util._clockid = 17