diff --git a/activitypub.py b/activitypub.py index 7a91aad..6884f83 100644 --- a/activitypub.py +++ b/activitypub.py @@ -165,7 +165,7 @@ class ActivityPub(Protocol): error('Invalid Digest header, required for HTTP Signature', status=401) try: - key_actor = cls.get_object(keyId) + key_actor = cls.load(keyId) except BadGateway: obj_id = as1.get_object(activity).get('id') if (activity.get('type') == 'Delete' and obj_id and diff --git a/follow.py b/follow.py index e0b8b52..282af0c 100644 --- a/follow.py +++ b/follow.py @@ -159,7 +159,7 @@ class FollowCallback(indieauth.Callback): return redirect(f'/user/{domain}/following') # TODO: make this generic across protocols - followee = activitypub.ActivityPub.get_object(as2_url).as2 + followee = activitypub.ActivityPub.load(as2_url).as2 id = followee.get('id') inbox = followee.get('inbox') if not id or not inbox: @@ -237,7 +237,7 @@ class UnfollowCallback(indieauth.Callback): if isinstance(followee, str): # fetch as AS2 to get full followee with inbox followee_id = followee - followee = activitypub.ActivityPub.get_object(followee_id).as2 + followee = activitypub.ActivityPub.load(followee_id).as2 inbox = followee.get('inbox') if not inbox: diff --git a/models.py b/models.py index 6d53dcb..71d6675 100644 --- a/models.py +++ b/models.py @@ -342,13 +342,12 @@ class Object(StringIdModel): self.labels.remove('activity') def _post_put_hook(self, future): - """Update :meth:`Protocol.get_object` cache.""" + """Update :meth:`Protocol.load` cache.""" # TODO: assert that as1 id is same as key id? in pre put hook? logger.info(f'Wrote Object {self.key.id()} {self.type} {self.status or ""} {self.labels} for {len(self.domains)} users') if '#' not in self.key.id(): - get_object = protocol.Protocol.get_object - key = get_object.cache_key(protocol.Protocol, self.key.id()) - get_object.cache[key] = self + key = protocol.Protocol.load.cache_key(protocol.Protocol, self.key.id()) + protocol.Protocol.load.cache[key] = self def clear(self): """Clears all data properties.""" diff --git a/protocol.py b/protocol.py index 19fcaeb..8b08c1b 100644 --- a/protocol.py +++ b/protocol.py @@ -201,12 +201,12 @@ class Protocol: # fetch actor if necessary so we have name, profile photo, etc if actor and actor.keys() == set(['id']): - actor = obj.as2['actor'] = cls.get_object(actor['id']).as2 + actor = obj.as2['actor'] = cls.load(actor['id']).as2 # fetch object if necessary so we can render it in feeds if obj.type == 'share' and inner_obj.keys() == set(['id']): inner_obj = obj.as2['object'] = as2.from_as1( - cls.get_object(inner_obj_id).as1) + cls.load(inner_obj_id).as1) if obj.type == 'follow': cls.accept_follow(obj) @@ -360,7 +360,7 @@ class Protocol: @classmethod @cached(LRUCache(1000), key=lambda cls, id: util.fragmentless(id), lock=threading.Lock()) - def get_object(cls, id): + def load(cls, id): """Loads and returns an Object from memory cache, datastore, or HTTP fetch. Assumes id is a URL. Any fragment at the end is stripped before loading. diff --git a/tests/test_activitypub.py b/tests/test_activitypub.py index 713f26d..33b8f1d 100644 --- a/tests/test_activitypub.py +++ b/tests/test_activitypub.py @@ -831,7 +831,7 @@ class ActivityPubTest(testutil.TestCase): _, mock_get, ___): # actor with a public key self.key_id_obj.key.delete() - Protocol.get_object.cache.clear() + Protocol.load.cache.clear() mock_get.return_value = self.as2_resp({ **ACTOR, 'publicKey': { @@ -909,7 +909,7 @@ class ActivityPubTest(testutil.TestCase): def test_delete_actor_not_fetchable(self, _, mock_get, ___): self.key_id_obj.key.delete() - Protocol.get_object.cache.clear() + Protocol.load.cache.clear() mock_get.return_value = requests_response(status=410) got = self.post('/inbox', json={**DELETE, 'object': 'http://my/key/id'}) @@ -919,7 +919,7 @@ class ActivityPubTest(testutil.TestCase): self.key_id_obj.as2 = None self.key_id_obj.deleted = True self.key_id_obj.put() - Protocol.get_object.cache.clear() + Protocol.load.cache.clear() got = self.post('/inbox', json={**DELETE, 'object': 'http://my/key/id'}) self.assertEqual(202, got.status_code) @@ -945,7 +945,7 @@ class ActivityPubTest(testutil.TestCase): labels=['activity']) obj.deleted = True - self.assert_entities_equal(obj, Protocol.get_object.cache['http://an/obj']) + self.assert_entities_equal(obj, Protocol.load.cache['http://an/obj']) def test_update_note(self, *mocks): Object(id='https://a/note', as2={}).put() @@ -970,7 +970,7 @@ class ActivityPubTest(testutil.TestCase): labels=['activity']) self.assert_entities_equal(Object.get_by_id('https://a/note'), - Protocol.get_object.cache['https://a/note']) + Protocol.load.cache['https://a/note']) def test_inbox_webmention_discovery_connection_fails(self, mock_head, mock_get, mock_post): @@ -1263,14 +1263,14 @@ class ActivityPubUtilsTest(testutil.TestCase): # TODO: make these generic and use FakeProtocol @patch('requests.get') - def test_get_object_http(self, mock_get): + def test_load_http(self, mock_get): mock_get.return_value = AS2 id = 'http://the/id' self.assertIsNone(Object.get_by_id(id)) # first time fetches over HTTP - got = ActivityPub.get_object(id) + got = ActivityPub.load(id) self.assert_equals(id, got.key.id()) self.assert_equals(AS2_OBJ, got.as2) mock_get.assert_has_calls([self.as2_req(id)]) @@ -1279,49 +1279,49 @@ class ActivityPubUtilsTest(testutil.TestCase): got.key.delete() mock_get.reset_mock() - got = ActivityPub.get_object(id) + got = ActivityPub.load(id) self.assert_equals(id, got.key.id()) self.assert_equals(AS2_OBJ, got.as2) mock_get.assert_not_called() @patch('requests.get') - def test_get_object_datastore(self, mock_get): + def test_load_datastore(self, mock_get): id = 'http://the/id' stored = Object(id=id, as2=AS2_OBJ) stored.put() - Protocol.get_object.cache.clear() + Protocol.load.cache.clear() # first time loads from datastore - got = ActivityPub.get_object(id) + got = ActivityPub.load(id) self.assert_entities_equal(stored, got) mock_get.assert_not_called() # second time is in cache stored.key.delete() - got = ActivityPub.get_object(id) + got = ActivityPub.load(id) self.assert_entities_equal(stored, got) mock_get.assert_not_called() @patch('requests.get') - def test_get_object_strips_fragment(self, mock_get): + def test_load_strips_fragment(self, mock_get): stored = Object(id='http://the/id', as2=AS2_OBJ) stored.put() - Protocol.get_object.cache.clear() + Protocol.load.cache.clear() - got = ActivityPub.get_object('http://the/id#ignore') + got = ActivityPub.load('http://the/id#ignore') self.assert_entities_equal(stored, got) mock_get.assert_not_called() @patch('requests.get') - def test_get_object_datastore_no_as2(self, mock_get): + def test_load_datastore_no_as2(self, mock_get): """If the stored Object has no as2, we should fall back to HTTP.""" id = 'http://the/id' stored = Object(id=id, as2={}, status='in progress') stored.put() - Protocol.get_object.cache.clear() + Protocol.load.cache.clear() mock_get.return_value = AS2 - got = ActivityPub.get_object(id) + got = ActivityPub.load(id) mock_get.assert_has_calls([self.as2_req(id)]) self.assert_equals(id, got.key.id()) diff --git a/tests/test_models.py b/tests/test_models.py index 69fc224..8b74cc4 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -295,20 +295,20 @@ class ObjectTest(testutil.TestCase): 'href="/user/user.com"> Alice', obj.actor_link()) - def test_put_updates_get_object_cache(self): + def test_put_updates_load_cache(self): obj = Object(id='x', as2={}) obj.put() - key = Protocol.get_object.cache_key(Protocol, 'x') - self.assert_entities_equal(obj, Protocol.get_object.cache[key]) + key = Protocol.load.cache_key(Protocol, 'x') + self.assert_entities_equal(obj, Protocol.load.cache[key]) - def test_put_fragment_id_doesnt_update_get_object_cache(self): + def test_put_fragment_id_doesnt_update_load_cache(self): obj = Object(id='x#y', as2={}) obj.put() - self.assertNotIn(Protocol.get_object.cache_key(Protocol, 'x#y'), - Protocol.get_object.cache) - self.assertNotIn(Protocol.get_object.cache_key(Protocol, 'x'), - Protocol.get_object.cache) + self.assertNotIn(Protocol.load.cache_key(Protocol, 'x#y'), + Protocol.load.cache) + self.assertNotIn(Protocol.load.cache_key(Protocol, 'x'), + Protocol.load.cache) def test_computed_properties_without_as1(self): Object(id='a').put() diff --git a/tests/test_protocol.py b/tests/test_protocol.py index 621debd..594dc5f 100644 --- a/tests/test_protocol.py +++ b/tests/test_protocol.py @@ -59,23 +59,23 @@ class ProtocolTest(testutil.TestCase): type='comment', ) - def test_get_object(self): + def test_load(self): obj = Object(id='foo', our_as1={'x': 'y'}) FakeProtocol.objects = {'foo': obj} - self.assert_entities_equal(obj, FakeProtocol.get_object('foo')) + self.assert_entities_equal(obj, FakeProtocol.load('foo')) self.assertIsNotNone(Object.get_by_id('foo')) self.assertEqual(['foo'], FakeProtocol.fetched) - def test_get_object_already_stored(self): + def test_load_already_stored(self): stored = Object(id='foo', our_as1={'x': 'y'}) stored.put() - self.assert_entities_equal(stored, FakeProtocol.get_object('foo')) + self.assert_entities_equal(stored, FakeProtocol.load('foo')) self.assertEqual([], FakeProtocol.fetched) @patch('requests.get') - def test_get_object_empty_deleted(self, mock_get): + def test_load_empty_deleted(self, mock_get): stored = Object(id='foo', deleted=True) stored.put() - self.assert_entities_equal(stored, FakeProtocol.get_object('foo')) + self.assert_entities_equal(stored, FakeProtocol.load('foo')) mock_get.assert_not_called() diff --git a/tests/testutil.py b/tests/testutil.py index b73ee1f..401e5e1 100644 --- a/tests/testutil.py +++ b/tests/testutil.py @@ -71,7 +71,7 @@ class TestCase(unittest.TestCase, testutil.Asserts): app.testing = True cache.clear() protocol.seen_ids.clear() - protocol.Protocol.get_object.cache.clear() + protocol.Protocol.load.cache.clear() common.webmention_discover.cache.clear() FakeProtocol.objects = {} diff --git a/webmention.py b/webmention.py index 84c3ae0..4278749 100644 --- a/webmention.py +++ b/webmention.py @@ -366,7 +366,7 @@ class WebmentionView(View): # fetch target page as AS2 object try: # TODO: make this generic across protocols - target_stored = activitypub.ActivityPub.get_object(target) + target_stored = activitypub.ActivityPub.load(target) target_obj = target_stored.as2 or as2.from_as1(target_stored.as1) except (requests.HTTPError, BadGateway) as e: resp = getattr(e, 'requests_response', None) @@ -392,7 +392,7 @@ class WebmentionView(View): if not inbox_url: # fetch actor as AS object # TODO: make this generic across protocols - actor_obj = activitypub.ActivityPub.get_object(actor) + actor_obj = activitypub.ActivityPub.load(actor) actor = actor_obj.as2 or as2.from_as1(actor_obj.as1) inbox_url = actor.get('inbox')