AP Follow: store users' followers in the datastore

#21
create
Ryan Barrett 2018-10-21 17:37:33 -07:00
rodzic a4b309afef
commit abc5ecd919
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
3 zmienionych plików z 39 dodań i 5 usunięć

Wyświetl plik

@ -14,7 +14,7 @@ from oauth_dropins.webutil import util
import webapp2
import common
from models import MagicKey, Response
from models import Follower, MagicKey, Response
from httpsig.requests_auth import HTTPSignatureAuth
SUPPORTED_TYPES = (
@ -154,7 +154,11 @@ class InboxHandler(webapp2.RequestHandler):
if not inbox:
common.error(self, 'Found no inbox for actor %s', actor)
# store Follower
user_domain = util.domain_from_link(common.redirect_unwrap(obj))
Follower.get_or_create(user_domain, actor, last_follow=json.dumps(follow))
# send AP Accept
accept = {
'@context': 'https://www.w3.org/ns/activitystreams',
'id': util.tag_uri(appengine_config.HOST, 'accept/%s/%s' % (

Wyświetl plik

@ -122,3 +122,28 @@ class Response(StringIdModel):
@classmethod
def _decode(cls, val):
return val.replace('__', '#')
class Follower(StringIdModel):
"""A follower of a Bridgy Fed user.
Key name is 'USER_DOMAIN FOLLOWER_ID', e.g.:
'snarfed.org https://mastodon.social/@swentel'.
"""
# most recent AP Follow activity (JSON)
last_follow = ndb.TextProperty()
created = ndb.DateTimeProperty(auto_now_add=True)
updated = ndb.DateTimeProperty(auto_now=True)
@classmethod
def _id(cls, user_domain, follower_id):
assert user_domain
assert follower_id
return '%s %s' % (user_domain, follower_id)
@classmethod
def get_or_create(cls, user_domain, follower_id, **kwargs):
logging.info('new Follower for %s %s', user_domain, follower_id)
return cls.get_or_insert(cls._id(user_domain, follower_id), **kwargs)

Wyświetl plik

@ -16,7 +16,7 @@ import requests
import activitypub
from activitypub import app
import common
from models import MagicKey, Response
from models import Follower, MagicKey, Response
import testutil
@ -198,9 +198,10 @@ class ActivityPubTest(testutil.TestCase):
self.assertEqual(like_activity, json.loads(resp.source_as2))
def test_inbox_follow_accept(self, mock_get, mock_post):
follower = FOLLOW_WRAPPED['actor']
actor = {
'@context': 'https://www.w3.org/ns/activitystreams',
'id': FOLLOW_WRAPPED['actor'],
'id': follower,
'type': 'Person',
'inbox': 'http://follower/inbox',
}
@ -217,14 +218,18 @@ class ActivityPubTest(testutil.TestCase):
as2_headers = copy.deepcopy(common.HEADERS)
as2_headers.update(common.CONNEG_HEADERS_AS2_HTML)
mock_get.assert_has_calls((
call(FOLLOW_WRAPPED['actor'], headers=as2_headers, timeout=15),
call(follower, headers=as2_headers, timeout=15),
))
args, kwargs = mock_post.call_args
self.assertEquals(('http://follower/inbox',), args)
self.assertEquals(ACCEPT, kwargs['json'])
# TODO: check webmention, Response
# check that we stored a Follower object
follower = Follower.get_by_id('realize.be %s' % (follower))
self.assertEqual(FOLLOW_WRAPPED, json.loads(follower.last_follow))
# TODO: check webmention
def test_inbox_unsupported_type(self, mock_get, mock_post):
got = app.get_response('/foo.com/inbox', method='POST', body=json.dumps({