From 2fad8e1c241954610a797840d9c0a786a3651c00 Mon Sep 17 00:00:00 2001 From: Ryan Barrett Date: Tue, 17 Sep 2024 13:34:57 -0700 Subject: [PATCH] Bluesky => fediverse: link mentions of non-bridged users to their bsky.app profile fixes #1288 --- ids.py | 3 +++ tests/test_activitypub.py | 57 +++++++++++++++++++++++++++++++++++++++ tests/test_ids.py | 11 +++++++- 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/ids.py b/ids.py index 1bf9a237..f40375d9 100644 --- a/ids.py +++ b/ids.py @@ -148,6 +148,9 @@ def translate_user_id(*, id, from_, to): return id case _, 'activitypub' | 'web': + from activitypub import ActivityPub + if user and not user.is_enabled(ActivityPub): + return user.web_url() return subdomain_wrap(from_, f'/{to.ABBREV}/{id}') # only for unit tests diff --git a/tests/test_activitypub.py b/tests/test_activitypub.py index bcae33a9..23bfc4ab 100644 --- a/tests/test_activitypub.py +++ b/tests/test_activitypub.py @@ -2819,6 +2819,63 @@ def test_convert_quote_post(self): }], }, ActivityPub.convert(obj), ignore=['contentMap', 'content_is_html', 'to']) + def test_send_convert_mention_non_bridged_id_uses_profile_url(self): + self.store_object(id='did:plc:5zspv27pk4iqtrl2ql2nykjh', raw={'foo': 'bar'}) + self.make_user(id='did:plc:5zspv27pk4iqtrl2ql2nykjh', cls=ATProto) + obj = Object(our_as1={ + 'objectType': 'note', + 'content': 'hello @snarfed2.bsky.social', + 'tags': [{ + 'objectType': 'mention', + 'url': 'did:plc:5zspv27pk4iqtrl2ql2nykjh', + 'displayName': '@snarfed2.bsky.social', + 'startIndex': 6, + 'length': 21, + }], + }) + self.assertEqual({ + '@context': 'https://www.w3.org/ns/activitystreams', + 'type': 'Note', + 'content': '

hello @snarfed2.bsky.social

', + 'contentMap': {'en': '

hello @snarfed2.bsky.social

'}, + 'tag': [{ + 'type': 'Mention', + 'name': '@snarfed2.bsky.social', + 'href': 'https://bsky.app/profile/did:plc:5zspv27pk4iqtrl2ql2nykjh', + }], + 'to': ['https://www.w3.org/ns/activitystreams#Public'], + 'cc': ['https://bsky.app/profile/did:plc:5zspv27pk4iqtrl2ql2nykjh'], + 'content_is_html': True, + }, ActivityPub.convert(obj)) + + @patch('requests.post', return_value=requests_response()) + def test_send_dm(self, mock_post): + bot = self.make_user('web.brid.gy', cls=Web) + user = self.make_user(ACTOR['id'], cls=ActivityPub, obj_as2=ACTOR) + + dm = Object(id='https://internal.brid.gy/dm', source_protocol='web', our_as1={ + 'objectType': 'note', + 'author': 'web.brid.gy', + 'content': 'hello world', + 'to': [ACTOR['id']], + }) + dm.put() + self.assertTrue(ActivityPub.send(dm, ACTOR['inbox'], from_user=bot)) + + self.assertEqual(1, len(mock_post.call_args_list)) + args, kwargs = mock_post.call_args_list[0] + self.assertEqual((ACTOR['inbox'],), args) + self.assertEqual({ + '@context': 'https://www.w3.org/ns/activitystreams', + 'type': 'Note', + 'id': 'http://localhost/r/https://internal.brid.gy/dm', + 'attributedTo': 'https://web.brid.gy/web.brid.gy', + 'content': '

hello world

', + 'contentMap': {'en': '

hello world

'}, + 'content_is_html': True, + 'to': [ACTOR['id']], + }, json_loads(kwargs['data'])) + def test_postprocess_as2_idempotent(self): for obj in (ACTOR, REPLY_OBJECT, REPLY_OBJECT_WRAPPED, REPLY, NOTE_OBJECT, NOTE, MENTION_OBJECT, MENTION, LIKE, diff --git a/tests/test_ids.py b/tests/test_ids.py index 96b520fb..eaf0d4d8 100644 --- a/tests/test_ids.py +++ b/tests/test_ids.py @@ -25,13 +25,19 @@ def test_translate_user_id(self): Fake(id='fake:user', copies=[Target(uri='did:plc:789', protocol='atproto')]).put() - # DID doc and ATProto, used to resolve handle in bsky.app URL + # ATProto with DID docs, used to resolve handle in bsky.app URL did = self.store_object(id='did:plc:123', raw={ 'id': 'did:plc:123', 'alsoKnownAs': ['at://user.com'], }) ATProto(id='did:plc:123', obj_key=did.key).put() + did = self.store_object(id='did:plc:000', raw={ + 'id': 'did:plc:000', + 'alsoKnownAs': ['at://zero.com'], + }) + ATProto(id='did:plc:000').put() + for from_, id, to, expected in [ (ActivityPub, 'https://inst/user', ActivityPub, 'https://inst/user'), (ActivityPub, 'https://inst/user', ATProto, 'did:plc:456'), @@ -54,6 +60,9 @@ def test_translate_user_id(self): (ATProto, 'https://bsky.app/profile/user.com', ATProto, 'did:plc:123'), (ATProto, 'https://bsky.app/profile/did:plc:123', ATProto, 'did:plc:123'), + # user, not enabled, no copy + (ATProto, 'did:plc:000', ActivityPub, 'https://bsky.app/profile/zero.com'), + (Fake, 'fake:user', ActivityPub, 'https://fa.brid.gy/ap/fake:user'), (Fake, 'fake:user', ATProto, 'did:plc:789'), (Fake, 'fake:user', Fake, 'fake:user'),