kopia lustrzana https://github.com/snarfed/bridgy-fed
follow UI: synthesize Follow activity id, store an Activity, link address, form bug fix
rodzic
c50f0e0106
commit
91c4200bb3
24
follow.py
24
follow.py
|
@ -13,11 +13,12 @@ from oauth_dropins import indieauth
|
|||
from oauth_dropins.webutil import flask_util, util
|
||||
from oauth_dropins.webutil.flask_util import error, flash
|
||||
from oauth_dropins.webutil import util
|
||||
from oauth_dropins.webutil.testutil import NOW
|
||||
from oauth_dropins.webutil.util import json_dumps, json_loads
|
||||
|
||||
from app import app
|
||||
import common
|
||||
from models import Follower, User
|
||||
from models import Activity, Follower, User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -120,9 +121,6 @@ class FollowCallback(indieauth.Callback):
|
|||
if not User.get_by_id(domain):
|
||||
error(f'No user for domain {domain}')
|
||||
|
||||
# addr = state.get('address')
|
||||
# if not addr:
|
||||
# error(f'state missing address field')
|
||||
addr = state
|
||||
assert addr
|
||||
webfinger = fetch_webfinger(addr)
|
||||
|
@ -146,18 +144,25 @@ class FollowCallback(indieauth.Callback):
|
|||
flash(f"AS2 profile {as2_url} missing id or inbox")
|
||||
return redirect(f'/user/{domain}/following')
|
||||
|
||||
common.signed_post(inbox, data={
|
||||
timestamp = NOW.replace(microsecond=0, tzinfo=None).isoformat()
|
||||
follow_as2 = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'type': 'Follow',
|
||||
'id': 'TODO',
|
||||
'id': common.host_url(f'/user/{domain}/following#{timestamp}-{addr}'),
|
||||
'object': id,
|
||||
'actor': common.host_url(domain),
|
||||
'to': [as2.PUBLIC_AUDIENCE],
|
||||
})
|
||||
}
|
||||
common.signed_post(inbox, data=follow_as2)
|
||||
|
||||
Follower.get_or_create(dest=id, src=domain, status='active',
|
||||
last_follow=json_dumps({}))
|
||||
flash(f'Followed {addr}.')
|
||||
Activity.get_or_create(source='UI', target=id, domain=[domain],
|
||||
direction='out', protocol='activitypub', status='complete',
|
||||
source_as2=json_dumps(follow_as2, sort_keys=True))
|
||||
|
||||
link = util.pretty_link(obj.get('url') or id, text=addr)
|
||||
flash(f'Followed {link}.')
|
||||
return redirect(f'/user/{domain}/following')
|
||||
|
||||
|
||||
|
@ -165,4 +170,5 @@ app.add_url_rule('/follow/start',
|
|||
view_func=FollowStart.as_view('follow_start', '/follow/callback'),
|
||||
methods=['POST'])
|
||||
app.add_url_rule('/follow/callback',
|
||||
view_func=FollowCallback.as_view('follow_callback', 'unused'))
|
||||
view_func=FollowCallback.as_view('follow_callback', 'unused'),
|
||||
methods=['GET'])
|
||||
|
|
|
@ -333,8 +333,8 @@ class Follower(StringIdModel):
|
|||
|
||||
src = ndb.StringProperty()
|
||||
dest = ndb.StringProperty()
|
||||
# most recent AP Follow activity (JSON). must have a composite actor object
|
||||
# with an inbox, publicInbox, or sharedInbox!
|
||||
# Most recent AP Follow activity (JSON). If this is an inbound follow, must
|
||||
# have a composite actor object with an inbox, publicInbox, or sharedInbox.
|
||||
last_follow = ndb.TextProperty()
|
||||
status = ndb.StringProperty(choices=STATUSES, default='active')
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<div class="row big">Following</div>
|
||||
|
||||
<div class="row">
|
||||
<form method="post" action="/follow">
|
||||
<form method="post" action="/follow/start">
|
||||
<p>
|
||||
<label for="follower-address">Add a follower (requires <a href="https://indieauth.net/">IndieAuth</a>):</label>
|
||||
<input id="follower-address" name="address" type="text" required
|
||||
|
|
|
@ -10,7 +10,7 @@ from oauth_dropins.webutil.testutil import requests_response
|
|||
from oauth_dropins.webutil.util import json_dumps, json_loads
|
||||
|
||||
import common
|
||||
from models import Follower, User
|
||||
from models import Activity, Follower, User
|
||||
from . import testutil
|
||||
|
||||
WEBFINGER = requests_response({
|
||||
|
@ -119,6 +119,7 @@ class AddFollowerTest(testutil.TestCase):
|
|||
self.as2_resp({
|
||||
'type': 'Person',
|
||||
'id': 'https://bar/id',
|
||||
'url': 'https://bar/url',
|
||||
'inbox': 'http://bar/inbox',
|
||||
}),
|
||||
)
|
||||
|
@ -133,7 +134,7 @@ class AddFollowerTest(testutil.TestCase):
|
|||
resp = self.client.get(f'/follow/callback?code=my_code&state={state}')
|
||||
self.assertEqual(302, resp.status_code)
|
||||
self.assertEqual('/user/snarfed.org/following',resp.headers['Location'])
|
||||
self.assertEqual(['Followed @foo@bar.'], get_flashed_messages())
|
||||
self.assertEqual(['Followed <a href="https://bar/url">@foo@bar</a>.'], get_flashed_messages())
|
||||
|
||||
mock_get.assert_has_calls((
|
||||
self.req('https://bar/.well-known/webfinger?resource=acct:foo@bar'),
|
||||
|
@ -150,19 +151,29 @@ class AddFollowerTest(testutil.TestCase):
|
|||
))
|
||||
inbox_args, inbox_kwargs = mock_post.call_args_list[-1]
|
||||
self.assertEqual(('http://bar/inbox',), inbox_args)
|
||||
self.assert_equals({
|
||||
|
||||
expected_follow = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'type': 'Follow',
|
||||
'id': 'TODO',
|
||||
'id': 'http://localhost/user/snarfed.org/following#2022-01-02T03:04:05-@foo@bar',
|
||||
'actor': 'http://localhost/snarfed.org',
|
||||
'object': 'https://bar/id',
|
||||
'to': [as2.PUBLIC_AUDIENCE],
|
||||
}, json_loads(inbox_kwargs['data']))
|
||||
}
|
||||
self.assert_equals(expected_follow, json_loads(inbox_kwargs['data']))
|
||||
|
||||
followers = Follower.query().fetch()
|
||||
self.assertEqual(1, len(followers))
|
||||
self.assertEqual('https://bar/id snarfed.org', followers[0].key.id())
|
||||
|
||||
activities = Activity.query().fetch()
|
||||
self.assert_entities_equal(
|
||||
[Activity(id='UI https://bar/id', domain=['snarfed.org'],
|
||||
status='complete', protocol='activitypub', direction='out',
|
||||
source_as2=json_dumps(expected_follow, sort_keys=True))],
|
||||
activities,
|
||||
ignore=['created', 'updated'])
|
||||
|
||||
def test_callback_missing_user(self, mock_get, mock_post):
|
||||
mock_post.return_value = requests_response('me=https://snarfed.org')
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue