start on AP followers/following collections

for #264
pull/311/head
Ryan Barrett 2022-11-21 18:46:10 -08:00
rodzic da6288972a
commit 2279db46fc
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
3 zmienionych plików z 134 dodań i 3 usunięć

Wyświetl plik

@ -259,3 +259,62 @@ def undo_follow(undo_unwrapped):
logger.warning(f'No Follower found for {user_domain} {follower}')
# TODO send webmention with 410 of u-follow
# TODO: unify with following_collection
@app.get(f'/<regex("{common.DOMAIN_RE}"):domain>/followers')
@flask_util.cached(cache, CACHE_TIME)
def followers_collection(domain):
"""ActivityPub Followers collection.
https://www.w3.org/TR/activitypub/#followers
https://www.w3.org/TR/activitypub/#collections
https://www.w3.org/TR/activitystreams-core/#paging
"""
if not User.get_by_id(domain):
return f'User {domain} not found', 404
logger.info(f"Counting {domain}'s followers")
count = Follower.query(
Follower.status == 'active',
Follower.dest == domain,
).count()
ret = {
'@context': 'https://www.w3.org/ns/activitystreams',
'summary': f"{domain}'s followers",
'type': 'Collection',
'totalItems': count,
'items': [], # TODO
}
logger.info(f'Returning {json_dumps(ret, indent=2)}')
return ret
@app.get(f'/<regex("{common.DOMAIN_RE}"):domain>/following')
@flask_util.cached(cache, CACHE_TIME)
def following_collection(domain):
"""ActivityPub Following collection.
https://www.w3.org/TR/activitypub/#following
https://www.w3.org/TR/activitypub/#collections
https://www.w3.org/TR/activitystreams-core/#paging
"""
if not User.get_by_id(domain):
return f'User {domain} not found', 404
logger.info(f"Counting {domain}'s following")
count = Follower.query(
Follower.status == 'active',
Follower.src == domain,
).count()
ret = {
'@context': 'https://www.w3.org/ns/activitystreams',
'summary': f"{domain}'s following",
'type': 'Collection',
'totalItems': count,
'items': [], # TODO
}
logger.info(f'Returning {json_dumps(ret, indent=2)}')
return ret

Wyświetl plik

@ -99,8 +99,6 @@ def user(domain):
@app.get(f'/user/<regex("{common.DOMAIN_RE}"):domain>/followers')
def followers(domain):
# TODO:
# pull more info from last_follow, eg name, profile picture, url
# unify with following
if not User.get_by_id(domain):
return render_template('user_not_found.html', domain=domain), 404
@ -116,7 +114,6 @@ def followers(domain):
f.handle = re.sub(r'^https?://(.+)/(users/|@)(.+)$', r'@\3@\1', f.src)
if f.last_follow:
last_follow = json_loads(f.last_follow)
print('@', last_follow)
actor = last_follow.get('actor', {})
f.name = actor.get('name') or ''
f.picture = actor.get('icon', {}).get('url')

Wyświetl plik

@ -520,3 +520,78 @@ class ActivityPubTest(testutil.TestCase):
self.assertEqual('in', activity.direction)
self.assertEqual('activitypub', activity.protocol)
self.assertEqual('ignored', activity.status)
def test_followers_collection_unknown_user(self, *args):
resp = self.client.get('/foo.com/followers')
self.assertEqual(404, resp.status_code)
def test_followers_collection(self, *args):
User.get_or_create('foo.com')
resp = self.client.get('/foo.com/followers')
self.assertEqual(200, resp.status_code)
self.assertEqual({
'@context': 'https://www.w3.org/ns/activitystreams',
'summary': "foo.com's followers",
'type': 'Collection',
'totalItems': 0,
'items': [],
}, resp.json)
Follower.get_or_create('foo.com', 'bar.com')
Follower.get_or_create('http://other/actor', 'foo.com')
Follower.get_or_create('foo.com', 'baz.com')
Follower.get_or_create('foo.com', 'baj.com', status='inactive')
resp = self.client.get('/foo.com/followers')
self.assertEqual(200, resp.status_code)
self.assertEqual({
'@context': 'https://www.w3.org/ns/activitystreams',
'summary': "foo.com's followers",
'type': 'Collection',
'totalItems': 2,
'items': [],
# TODO
# {
# 'type': 'Create',
# 'actor': 'http://www.test.example/sally',
# 'object': 'http://example.org/foo',
# },
# {
# 'type': 'Like',
# 'actor': 'http://www.test.example/joe',
# 'object': 'http://example.org/foo',
# }],
}, resp.json)
def test_following_collection_unknown_user(self, *args):
resp = self.client.get('/foo.com/following')
self.assertEqual(404, resp.status_code)
def test_following_collection(self, *args):
User.get_or_create('foo.com')
resp = self.client.get('/foo.com/following')
self.assertEqual(200, resp.status_code)
self.assertEqual({
'@context': 'https://www.w3.org/ns/activitystreams',
'summary': "foo.com's following",
'type': 'Collection',
'totalItems': 0,
'items': [],
}, resp.json)
Follower.get_or_create('bar.com', 'foo.com')
Follower.get_or_create('foo.com', 'http://other/actor')
Follower.get_or_create('baz.com', 'foo.com')
Follower.get_or_create('baj.com', 'foo.com', status='inactive')
resp = self.client.get('/foo.com/following')
self.assertEqual(200, resp.status_code)
self.assertEqual({
'@context': 'https://www.w3.org/ns/activitystreams',
'summary': "foo.com's following",
'type': 'Collection',
'totalItems': 2,
'items': [],
}, resp.json)