kopia lustrzana https://github.com/snarfed/bridgy-fed
make Follower.to_as1() handle both inbound and outbound last_follow
...and use it in followers and following UI pagespull/380/head
rodzic
02aa3e9801
commit
c3edf3a68e
|
@ -74,6 +74,7 @@ DOMAIN_BLOCKLIST = frozenset((
|
|||
_DEFAULT_SIGNATURE_USER = None
|
||||
|
||||
CACHE_TIME = datetime.timedelta(seconds=10)
|
||||
PAGE_SIZE = 20
|
||||
|
||||
|
||||
def host_url(path_query=None):
|
||||
|
@ -629,7 +630,7 @@ def fetch_page(query, model_class):
|
|||
query = query.order(-model_class.updated)
|
||||
|
||||
query_iter = query.iter()
|
||||
results = sorted(islice(query_iter, 0, PAGE_SIZE),
|
||||
results = sorted(itertools.islice(query_iter, 0, PAGE_SIZE),
|
||||
key=lambda r: r.updated, reverse=True)
|
||||
|
||||
# calculate new paging param(s)
|
||||
|
|
|
@ -367,6 +367,6 @@ class Follower(StringIdModel):
|
|||
"""Returns this follower as an AS1 actor dict, if possible."""
|
||||
if self.last_follow:
|
||||
last_follow = json_loads(self.last_follow)
|
||||
actor = last_follow.get('actor')
|
||||
if actor:
|
||||
return as2.to_as1(actor)
|
||||
person = last_follow.get('actor' if util.is_web(self.src) else 'object')
|
||||
if person:
|
||||
return as2.to_as1(person)
|
||||
|
|
24
pages.py
24
pages.py
|
@ -1,7 +1,6 @@
|
|||
"""UI pages."""
|
||||
import calendar
|
||||
import datetime
|
||||
from itertools import islice
|
||||
import logging
|
||||
import re
|
||||
import urllib.parse
|
||||
|
@ -16,9 +15,9 @@ from oauth_dropins.webutil.util import json_dumps, json_loads
|
|||
|
||||
from app import app, cache
|
||||
import common
|
||||
from common import DOMAIN_RE, PAGE_SIZE
|
||||
from models import Follower, User, Activity
|
||||
|
||||
PAGE_SIZE = 20
|
||||
ACTIVITIES_FETCH_LIMIT = 200
|
||||
FOLLOWERS_UI_LIMIT = 999
|
||||
|
||||
|
@ -65,12 +64,12 @@ def check_web_site():
|
|||
return redirect(f'/user/{user.key.id()}')
|
||||
|
||||
|
||||
@app.get(f'/responses/<regex("{common.DOMAIN_RE}"):domain>') # deprecated
|
||||
@app.get(f'/responses/<regex("{DOMAIN_RE}"):domain>') # deprecated
|
||||
def user_deprecated(domain):
|
||||
return redirect(f'/user/{domain}', code=301)
|
||||
|
||||
|
||||
@app.get(f'/user/<regex("{common.DOMAIN_RE}"):domain>')
|
||||
@app.get(f'/user/<regex("{DOMAIN_RE}"):domain>')
|
||||
def user(domain):
|
||||
user = User.get_by_id(domain)
|
||||
if not user:
|
||||
|
@ -102,7 +101,7 @@ def user(domain):
|
|||
)
|
||||
|
||||
|
||||
@app.get(f'/user/<regex("{common.DOMAIN_RE}"):domain>/<any(followers,following):collection>')
|
||||
@app.get(f'/user/<regex("{DOMAIN_RE}"):domain>/<any(followers,following):collection>')
|
||||
def followers_or_following(domain, collection):
|
||||
if not (user := User.get_by_id(domain)):
|
||||
return render_template('user_not_found.html', domain=domain), 404
|
||||
|
@ -113,18 +112,15 @@ def followers_or_following(domain, collection):
|
|||
Follower.status == 'active',
|
||||
domain_prop == domain,
|
||||
).order(-Follower.updated)
|
||||
followers, before, after = common.fetch_page(query, Follower)
|
||||
followers, before, after = fetch_page(query, Follower)
|
||||
|
||||
for f in followers:
|
||||
f.url = f.src if collection == 'followers' else f.dest
|
||||
f.handle = re.sub(r'^https?://(.+)/(users/|@)(.+)$', r'@\3@\1', f.url)
|
||||
if f.last_follow:
|
||||
last_follow = json_loads(f.last_follow)
|
||||
person = last_follow.get(
|
||||
'actor' if collection == 'followers' else 'object', {})
|
||||
if isinstance(person, dict):
|
||||
f.name = person.get('name') or ''
|
||||
f.picture = util.get_url(person, 'icon') or util.get_url(person, 'image')
|
||||
person = f.to_as1()
|
||||
if person and isinstance(person, dict):
|
||||
f.name = person.get('name') or ''
|
||||
f.picture = util.get_url(person, 'icon') or util.get_url(person, 'image')
|
||||
|
||||
return render_template(
|
||||
f'{collection}.html',
|
||||
|
@ -133,7 +129,7 @@ def followers_or_following(domain, collection):
|
|||
)
|
||||
|
||||
|
||||
@app.get(f'/user/<regex("{common.DOMAIN_RE}"):domain>/feed')
|
||||
@app.get(f'/user/<regex("{DOMAIN_RE}"):domain>/feed')
|
||||
def feed(domain):
|
||||
format = request.args.get('format', 'html')
|
||||
if format not in ('html', 'atom', 'rss'):
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
"""Unit tests for models.py."""
|
||||
from unittest import mock
|
||||
|
||||
from granary import as2
|
||||
from oauth_dropins.webutil.testutil import requests_response
|
||||
from oauth_dropins.webutil.util import json_dumps, json_loads
|
||||
|
||||
from app import app
|
||||
from models import User, Activity
|
||||
from models import Activity, Follower, User
|
||||
from . import testutil
|
||||
|
||||
from .test_activitypub import ACTOR
|
||||
|
||||
class UserTest(testutil.TestCase):
|
||||
|
||||
|
@ -189,3 +191,17 @@ class ActivityTest(testutil.TestCase):
|
|||
activity.source_as2 = 'as2'
|
||||
self.assertEqual('http://localhost/render?source=abc&target=xyz',
|
||||
activity.proxy_url())
|
||||
|
||||
|
||||
class FollowerTest(testutil.TestCase):
|
||||
def test_to_as1(self):
|
||||
self.assertIsNone(Follower().to_as1())
|
||||
|
||||
as1_actor = as2.to_as1(ACTOR)
|
||||
f = Follower(dest='foo.com', src='http://bar/@baz',
|
||||
last_follow=json_dumps({'actor': ACTOR}))
|
||||
self.assertEqual(as1_actor, f.to_as1())
|
||||
|
||||
f = Follower(dest='http://bar/@baz', src='foo.com',
|
||||
last_follow=json_dumps({'object': ACTOR}))
|
||||
self.assertEqual(as1_actor, f.to_as1())
|
||||
|
|
|
@ -7,7 +7,7 @@ from oauth_dropins.webutil.testutil import requests_response
|
|||
from oauth_dropins.webutil.util import json_dumps, json_loads
|
||||
import requests
|
||||
|
||||
from .test_activitypub import FOLLOW_WITH_ACTOR
|
||||
from .test_activitypub import ACTOR, FOLLOW
|
||||
from . import testutil
|
||||
from models import Follower
|
||||
|
||||
|
@ -35,11 +35,13 @@ FOLLOWERS_BSKY = [{
|
|||
'declaration': ACTOR_DECLARATION,
|
||||
'indexedAt': '2022-01-02T03:04:05+00:00',
|
||||
}]
|
||||
OTHER_FOLLOW_AS2 = copy.deepcopy(FOLLOW_WITH_ACTOR)
|
||||
OTHER_FOLLOW_AS2['actor'].update({
|
||||
FOLLOW_WITH_OBJECT_AS2 = copy.deepcopy(FOLLOW)
|
||||
FOLLOW_WITH_OBJECT_AS2['object'] = ACTOR
|
||||
OTHER_FOLLOW_AS2 = copy.deepcopy(FOLLOW)
|
||||
OTHER_FOLLOW_AS2['object'] = {
|
||||
'url': 'http://other',
|
||||
'preferredUsername': 'yoozer',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@patch('requests.get')
|
||||
|
@ -100,7 +102,7 @@ class XrpcGraphTest(testutil.TestCase):
|
|||
def test_getFollows(self, mock_get):
|
||||
Follower.get_or_create('https://no/stored/follow', 'foo.com')
|
||||
Follower.get_or_create('https://masto/user', 'foo.com',
|
||||
last_follow=json_dumps(FOLLOW_WITH_ACTOR))
|
||||
last_follow=json_dumps(FOLLOW_WITH_OBJECT_AS2))
|
||||
Follower.get_or_create( 'http://other', 'foo.com',
|
||||
last_follow=json_dumps(OTHER_FOLLOW_AS2))
|
||||
Follower.get_or_create('http://nope', 'nope.com',
|
||||
|
|
Ładowanie…
Reference in New Issue