From 4d2fcdd76f86be2bac1e56f4563fab70879e2bdc Mon Sep 17 00:00:00 2001 From: Ryan Barrett Date: Tue, 31 Jan 2023 21:00:07 -0800 Subject: [PATCH] Activity => Object: fully populate labels, source_protocol webmention #286 --- activitypub.py | 2 +- common.py | 4 +++- follow.py | 6 +++--- models.py | 6 +++--- tests/test_activitypub.py | 8 +++++++- tests/test_follow.py | 4 ++-- tests/test_webmention.py | 27 ++++++++++++++++++--------- webmention.py | 6 +++--- 8 files changed, 40 insertions(+), 23 deletions(-) diff --git a/activitypub.py b/activitypub.py index 6413a39..a609fd4 100644 --- a/activitypub.py +++ b/activitypub.py @@ -150,7 +150,7 @@ def inbox(domain=None): key = Object(id=source, source_protocol='activitypub', domains=domains, status='complete', as2=activity_as2_str, as1=activity_as1_str, type=as1_type, object_ids=as1.get_ids(activity_as1, 'object'), - ).put() + labels=['feed']).put() logging.info(f'Wrote Object {key} with {len(domains)} follower domains') return '' diff --git a/common.py b/common.py index 97fa081..e8c9a35 100644 --- a/common.py +++ b/common.py @@ -300,7 +300,9 @@ def send_webmentions(activity_wrapped, proxy=None, **object_props): logger.info(f'Skipping same-domain webmention from {source} to {target}') continue - obj = Object(id=source, domains=[domain], **object_props) + # TODO: unify across targets + obj = Object(id=source, domains=[domain], labels=['notification'], + **object_props) obj.put() wm_source = (obj.proxy_url() if verb in ('follow', 'like', 'share') or proxy diff --git a/follow.py b/follow.py index 2dab4d8..5af9ac5 100644 --- a/follow.py +++ b/follow.py @@ -167,7 +167,7 @@ class FollowCallback(indieauth.Callback): follow_json = json_dumps(follow_as2, sort_keys=True) Follower.get_or_create(dest=id, src=domain, status='active', last_follow=follow_json) - Object(id=follow_id, domains=[domain], labels=['notification'], + Object(id=follow_id, domains=[domain], labels=['user'], source_protocol='ui', status='complete', as2=follow_json, as1=json_dumps(as2.to_as1(follow_as2), sort_keys=True), ).put() @@ -193,7 +193,7 @@ class UnfollowStart(indieauth.Start): class UnfollowCallback(indieauth.Callback): - """IndieAuth callback to add a follower to an existing user.""" + """IndieAuth callback to remove a follower.""" def finish(self, auth_entity, state=None): if not auth_entity: return @@ -224,7 +224,7 @@ class UnfollowCallback(indieauth.Callback): follower.status = 'inactive' follower.put() - Object(id=unfollow_id, domains=[domain], labels=['notification'], + Object(id=unfollow_id, domains=[domain], labels=['user'], source_protocol='ui', status='complete', as2=json_dumps(unfollow_as2, sort_keys=True), as1=json_dumps(as2.to_as1(unfollow_as2), sort_keys=True), diff --git a/models.py b/models.py index 2526b6a..ec3167c 100644 --- a/models.py +++ b/models.py @@ -233,8 +233,8 @@ class Object(StringIdModel): Key name is the id. We synthesize ids if necessary. """ STATUSES = ('new', 'in progress', 'complete', 'failed', 'ignored') - PROTOCOLS = ('activitypub', 'bluesky', 'webmention', 'ui') - LABELS = ('feed', 'notification') + PROTOCOLS = ('activitypub', 'bluesky', 'ostatus', 'webmention', 'ui') + LABELS = ('feed', 'notification', 'user') # domains of the Bridgy Fed users this activity is to or from domains = ndb.StringProperty(repeated=True) @@ -251,7 +251,7 @@ class Object(StringIdModel): mf2 = ndb.TextProperty() # HTML microformats2 type = ndb.StringProperty() # AS1 objectType, or verb if it's an activity - deleted = ndb.BooleanProperty(default=False) + deleted = ndb.BooleanProperty() object_ids = ndb.StringProperty(repeated=True) # id(s) of inner objects # ActivityPub inbox delivery diff --git a/tests/test_activitypub.py b/tests/test_activitypub.py index 29942fb..f59775c 100644 --- a/tests/test_activitypub.py +++ b/tests/test_activitypub.py @@ -332,6 +332,7 @@ class ActivityPubTest(testutil.TestCase): source_protocol='activitypub', status='complete', as1=as2.to_as1(expected_props['as2']), + labels=['notification'], **expected_props) def test_inbox_reply_to_self_domain(self, mock_head, mock_get, mock_post): @@ -379,6 +380,7 @@ class ActivityPubTest(testutil.TestCase): as1=as2.to_as1(expected_as2), domains=['foo.com', 'baz.com'], type='post', + labels=['feed'], object_ids=[NOTE_OBJECT['id']]) def test_inbox_not_public(self, mock_head, mock_get, mock_post): @@ -440,6 +442,7 @@ class ActivityPubTest(testutil.TestCase): status='complete', as2=expected_as2, as1=as2.to_as1(expected_as2), + labels=['notification'], **expected_props) def test_inbox_like(self, mock_head, mock_get, mock_post): @@ -464,7 +467,6 @@ class ActivityPubTest(testutil.TestCase): args, kwargs = mock_post.call_args self.assertEqual(('http://or.ig/webmention',), args) self.assertEqual({ - # TODO 'source': 'http://localhost/render?id=http%3A%2F%2Fth.is%2Flike%23ok', 'target': 'http://or.ig/post', }, kwargs['data']) @@ -476,6 +478,7 @@ class ActivityPubTest(testutil.TestCase): as2=LIKE_WITH_ACTOR, as1=as2.to_as1(LIKE_WITH_ACTOR), type='like', + labels=['notification'], object_ids=[LIKE['object']]) def test_inbox_follow_accept_with_id(self, mock_head, mock_get, mock_post): @@ -492,6 +495,7 @@ class ActivityPubTest(testutil.TestCase): as2=follow, as1=as2.to_as1(follow), type='follow', + labels=['notification'], object_ids=[FOLLOW['object']]) follower = Follower.query().get() @@ -534,6 +538,7 @@ class ActivityPubTest(testutil.TestCase): as2=follow, as1=as2.to_as1(follow), type='follow', + labels=['notification'], object_ids=[FOLLOW['object']]) def _test_inbox_follow_accept(self, follow_as2, accept_as2, @@ -745,6 +750,7 @@ class ActivityPubTest(testutil.TestCase): as2=LIKE_WITH_ACTOR, as1=as2.to_as1(LIKE_WITH_ACTOR), type='like', + labels=['notification'], object_ids=[LIKE['object']]) def test_followers_collection_unknown_user(self, *args): diff --git a/tests/test_follow.py b/tests/test_follow.py index 725223c..d636d62 100644 --- a/tests/test_follow.py +++ b/tests/test_follow.py @@ -193,7 +193,7 @@ class FollowTest(testutil.TestCase): objects = Object.query().fetch() self.assert_entities_equal( [Object(id=id, domains=['snarfed.org'], status='complete', - labels=['notification'], source_protocol='ui', + labels=['user'], source_protocol='ui', as1=follow_as1, as2=follow_as2)], objects, ignore=['created', 'updated']) @@ -288,7 +288,7 @@ class UnfollowTest(testutil.TestCase): self.assert_entities_equal( [Object(id='http://localhost/user/snarfed.org/following#undo-2022-01-02T03:04:05-https://bar/id', domains=['snarfed.org'], status='complete', - source_protocol='ui', labels=['notification'], + source_protocol='ui', labels=['user'], as2=json_dumps(UNDO_FOLLOW, sort_keys=True), as1=json_dumps(as2.to_as1(UNDO_FOLLOW), sort_keys=True), )], diff --git a/tests/test_webmention.py b/tests/test_webmention.py index e1f07ff..fa26770 100644 --- a/tests/test_webmention.py +++ b/tests/test_webmention.py @@ -491,12 +491,13 @@ class WebmentionTest(testutil.TestCase): self.assert_object('http://a/reply', domains=['a'], - source_protocol='activitypub', + source_protocol='webmention', status='complete', ap_delivered=['https://foo.com/inbox'], mf2=self.reply_mf2, as1=self.reply_as1, type='comment', + labels=['user'], ) def test_update_reply(self, mock_get, mock_post): @@ -616,13 +617,14 @@ class WebmentionTest(testutil.TestCase): self.assert_object('http://a/repost', domains=['a'], - source_protocol='activitypub', + source_protocol='webmention', status='complete', mf2=self.repost_mf2, as1=self.repost_as1, ap_delivered=['https://foo.com/inbox'], type='share', object_ids=['https://orig/post'], + labels=['user'], ) def test_link_rel_alternate_as2(self, mock_get, mock_post): @@ -768,12 +770,13 @@ class WebmentionTest(testutil.TestCase): self.assert_object(f'https://orig/post', domains=['orig'], - source_protocol='activitypub', + source_protocol='webmention', status='complete', mf2=self.create_mf2, as1=self.create_as1, ap_delivered=inboxes, type='note', + labels=['user'], ) def test_create_post_run_task_resume(self, mock_get, mock_post): @@ -809,12 +812,13 @@ class WebmentionTest(testutil.TestCase): self.assert_object(f'https://orig/post', domains=['orig'], - source_protocol='activitypub', + source_protocol='webmention', status='complete', mf2=self.create_mf2, as1=self.create_as1, ap_delivered=inboxes + ['https://skipped/inbox'], type='note', + labels=['user'], ) def test_create_post_run_task_update(self, mock_get, mock_post): @@ -850,12 +854,13 @@ class WebmentionTest(testutil.TestCase): self.assert_object(f'https://orig/post', domains=['orig'], - source_protocol='activitypub', + source_protocol='webmention', status='complete', mf2=self.create_mf2, as1=self.create_as1, ap_delivered=inboxes, type='note', + labels=['user'], ) def test_create_with_image(self, mock_get, mock_post): @@ -912,13 +917,14 @@ class WebmentionTest(testutil.TestCase): self.assert_object('http://a/follow', domains=['a'], - source_protocol='activitypub', + source_protocol='webmention', status='complete', mf2=self.follow_mf2, as1=self.follow_as1, ap_delivered=['https://foo.com/inbox'], type='follow', object_ids=['http://followee'], + labels=['user'], ) followers = Follower.query().fetch() @@ -978,13 +984,14 @@ class WebmentionTest(testutil.TestCase): self.assert_object('http://a/follow#2', domains=['a'], - source_protocol='activitypub', + source_protocol='webmention', status='complete', mf2=self.follow_fragment_mf2, as1=self.follow_fragment_as1, ap_delivered=['https://foo.com/inbox'], type='follow', object_ids=['http://followee'], + labels=['user'], ) followers = Follower.query().fetch() @@ -1034,13 +1041,14 @@ class WebmentionTest(testutil.TestCase): self.assert_object('http://a/follow', domains=['a'], - source_protocol='activitypub', + source_protocol='webmention', status='failed', mf2=self.follow_mf2, as1=self.follow_as1, ap_failed=['https://foo.com/inbox'], type='follow', object_ids=['http://followee'], + labels=['user'], ) def test_repost_blocklisted_error(self, mock_get, mock_post): @@ -1119,11 +1127,12 @@ class WebmentionTest(testutil.TestCase): } self.assert_object(f'https://orig/', domains=['orig'], - source_protocol='activitypub', + source_protocol='webmention', status='complete', mf2=ACTOR_MF2, as1=expected_as1, ap_delivered=['https://inbox', 'https://shared/inbox'], type='update', object_ids=['https://orig'], + labels=['user'], ) diff --git a/webmention.py b/webmention.py index 810ec91..d02568e 100644 --- a/webmention.py +++ b/webmention.py @@ -156,16 +156,16 @@ class Webmention(View): else: obj = Object(id=self.source_url, ap_undelivered=list(inboxes_to_targets.keys()), - ap_delivered=[], - ap_failed=[]) + ap_delivered=[], ap_failed=[]) logging.info(f'Storing new {obj}') obj.domains = [self.source_domain] - obj.source_protocol = 'activitypub' + obj.source_protocol = 'webmention' obj.mf2 = json_dumps(self.source_mf2) obj.as1 = json_dumps(self.source_as1) obj.type = type obj.object_ids = as1.get_ids(self.source_as1, 'object') + obj.labels = ['user'] obj.put() # TODO: collect by inbox, add 'to' fields, de-dupe inboxes and recipients