kopia lustrzana https://github.com/snarfed/bridgy-fed
bluesky: implement app.bsky.graph.getFollowers
rodzic
84163938f3
commit
898b8545ac
13
models.py
13
models.py
|
@ -112,6 +112,11 @@ class User(StringIdModel):
|
||||||
base64_to_long(str(self.private_exponent))))
|
base64_to_long(str(self.private_exponent))))
|
||||||
return rsa.exportKey(format='PEM')
|
return rsa.exportKey(format='PEM')
|
||||||
|
|
||||||
|
def to_as1(self):
|
||||||
|
"""Returns this user as an AS1 actor dict, if possible."""
|
||||||
|
if self.actor_as2:
|
||||||
|
return as2.to_as1(json_loads(self.actor_as2))
|
||||||
|
|
||||||
def username(self):
|
def username(self):
|
||||||
"""Returns the user's preferred username from an acct: url, if available.
|
"""Returns the user's preferred username from an acct: url, if available.
|
||||||
|
|
||||||
|
@ -357,3 +362,11 @@ class Follower(StringIdModel):
|
||||||
setattr(follower, prop, val)
|
setattr(follower, prop, val)
|
||||||
follower.put()
|
follower.put()
|
||||||
return follower
|
return follower
|
||||||
|
|
||||||
|
def to_as1(self):
|
||||||
|
"""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)
|
||||||
|
|
|
@ -1,60 +1,86 @@
|
||||||
"""Unit tests for graph.py."""
|
"""Unit tests for graph.py."""
|
||||||
|
import copy
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from oauth_dropins.webutil import util
|
from granary import bluesky
|
||||||
from oauth_dropins.webutil.testutil import requests_response
|
from oauth_dropins.webutil.testutil import requests_response
|
||||||
|
from oauth_dropins.webutil.util import json_dumps, json_loads
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
from .test_activitypub import FOLLOW_WITH_ACTOR
|
||||||
from . import testutil
|
from . import testutil
|
||||||
|
from models import Follower
|
||||||
|
|
||||||
|
ACTOR_DECLARATION = {
|
||||||
|
'$type': 'app.bsky.system.declRef',
|
||||||
|
'actorType': 'app.bsky.system.actorUser',
|
||||||
|
'cid': 'TODO',
|
||||||
|
}
|
||||||
|
SUBJECT = {
|
||||||
|
'$type': 'app.bsky.actor.ref#withInfo',
|
||||||
|
'did': 'did:web:foo.com',
|
||||||
|
'handle': 'foo.com',
|
||||||
|
'declaration': ACTOR_DECLARATION,
|
||||||
|
}
|
||||||
|
FOLLOWERS_BSKY = [{
|
||||||
|
'$type': 'app.bsky.graph.getFollowers#follower',
|
||||||
|
'did': 'did:web:other',
|
||||||
|
'handle': 'other-username',
|
||||||
|
'declaration': ACTOR_DECLARATION,
|
||||||
|
'indexedAt': '2022-01-02T03:04:05+00:00',
|
||||||
|
}, {
|
||||||
|
'$type': 'app.bsky.graph.getFollowers#follower',
|
||||||
|
'did': 'did:web:mastodon.social:users:swentel',
|
||||||
|
'handle': 'mastodon.social/users/swentel',
|
||||||
|
'declaration': ACTOR_DECLARATION,
|
||||||
|
'indexedAt': '2022-01-02T03:04:05+00:00',
|
||||||
|
}]
|
||||||
|
|
||||||
|
|
||||||
# @patch('requests.get')
|
@patch('requests.get')
|
||||||
# class XrpcGraphTest(testutil.TestCase):
|
class XrpcGraphTest(testutil.TestCase):
|
||||||
|
|
||||||
# def test_getAuthorFeed(self, mock_get):
|
def test_getFollowers_not_domain(self, mock_get):
|
||||||
# mock_get.return_value = requests_response("""
|
resp = self.client.get('/xrpc/app.bsky.graph.getFollowers',
|
||||||
# <body>
|
query_string={'user': 'not a domain'})
|
||||||
# </body>
|
self.assertEqual(400, resp.status_code)
|
||||||
# """, url='https://foo.com/')
|
|
||||||
|
|
||||||
# got = self.client.get('/xrpc/app.bsky.actor.getProfile',
|
def test_getFollowers_empty(self, mock_get):
|
||||||
# query_string={'actor': 'foo.com'},
|
resp = self.client.get('/xrpc/app.bsky.graph.getFollowers',
|
||||||
# ).json
|
query_string={'user': 'foo.com'})
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
self.assert_equals({
|
||||||
|
'subject': SUBJECT,
|
||||||
|
'cursor': '',
|
||||||
|
'followers': [],
|
||||||
|
}, resp.json)
|
||||||
|
|
||||||
|
def test_getFollowers(self, mock_get):
|
||||||
|
Follower.get_or_create('foo.com', 'https://no/stored/follow')
|
||||||
|
Follower.get_or_create('foo.com', 'https://masto/user',
|
||||||
|
last_follow=json_dumps(FOLLOW_WITH_ACTOR))
|
||||||
|
|
||||||
|
other = copy.deepcopy(FOLLOW_WITH_ACTOR)
|
||||||
|
other['actor'].update({
|
||||||
|
'url': 'http://other',
|
||||||
|
'preferredUsername': 'other-username',
|
||||||
|
})
|
||||||
|
Follower.get_or_create('foo.com', 'http://other', last_follow=json_dumps(other))
|
||||||
|
|
||||||
|
other['actor']['url'] = 'http://nope'
|
||||||
|
Follower.get_or_create('nope.com', 'http://nope' , last_follow=json_dumps(other))
|
||||||
|
|
||||||
|
resp = self.client.get('/xrpc/app.bsky.graph.getFollowers',
|
||||||
|
query_string={'user': 'foo.com'})
|
||||||
|
self.assertEqual(200, resp.status_code)
|
||||||
|
self.assert_equals({
|
||||||
|
'subject': SUBJECT,
|
||||||
|
'cursor': '',
|
||||||
|
'followers': FOLLOWERS_BSKY,
|
||||||
|
}, resp.json)
|
||||||
|
|
||||||
|
# def test_getFollows(self, mock_get):
|
||||||
|
# resp = self.client.get('/xrpc/app.bsky.graph.getFollows',
|
||||||
|
# query_string={'user': 'foo.com'})
|
||||||
# self.assertEqual({
|
# self.assertEqual({
|
||||||
# }, got)
|
# }, resp.json)
|
||||||
|
|
||||||
# def test_getPostThread(self, mock_get):
|
|
||||||
# mock_get.return_value = requests_response("""
|
|
||||||
# <body>
|
|
||||||
# </body>
|
|
||||||
# """, url='https://foo.com/')
|
|
||||||
|
|
||||||
# got = self.client.get('/xrpc/app.bsky.actor.getProfile',
|
|
||||||
# query_string={'actor': 'foo.com'},
|
|
||||||
# ).json
|
|
||||||
# self.assertEqual({
|
|
||||||
# }, got)
|
|
||||||
|
|
||||||
# def test_getRepostedBy(self, mock_get):
|
|
||||||
# mock_get.return_value = requests_response("""
|
|
||||||
# <body>
|
|
||||||
# </body>
|
|
||||||
# """, url='https://foo.com/')
|
|
||||||
|
|
||||||
# got = self.client.get('/xrpc/app.bsky.actor.getProfile',
|
|
||||||
# query_string={'actor': 'foo.com'},
|
|
||||||
# ).json
|
|
||||||
# self.assertEqual({
|
|
||||||
# }, got)
|
|
||||||
|
|
||||||
# def test_getTimeline(self, mock_get):
|
|
||||||
# mock_get.return_value = requests_response("""
|
|
||||||
# <body>
|
|
||||||
# </body>
|
|
||||||
# """, url='https://foo.com/')
|
|
||||||
|
|
||||||
# got = self.client.get('/xrpc/app.bsky.actor.getProfile',
|
|
||||||
# query_string={'actor': 'foo.com'},
|
|
||||||
# ).json
|
|
||||||
# self.assertEqual({
|
|
||||||
# }, got)
|
|
||||||
|
|
|
@ -1,20 +1,45 @@
|
||||||
"""app.bsky.graph.* XRPC methods."""
|
"""app.bsky.graph.* XRPC methods."""
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
|
from granary import bluesky
|
||||||
|
from oauth_dropins.webutil import util
|
||||||
|
|
||||||
from app import xrpc_server
|
from app import xrpc_server
|
||||||
|
from models import Follower
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# get these from datastore
|
|
||||||
@xrpc_server.method('app.bsky.graph.getFollowers')
|
@xrpc_server.method('app.bsky.graph.getFollowers')
|
||||||
def getFollowers(input):
|
def getFollowers(input, user=None, limit=50, before=None):
|
||||||
"""
|
"""
|
||||||
lexicons/app/bsky/graph/getFollowers.json
|
lexicons/app/bsky/graph/getFollowers.json
|
||||||
"""
|
"""
|
||||||
|
# TODO: what is user?
|
||||||
|
if not re.match(util.DOMAIN_RE, user):
|
||||||
|
raise ValueError(f'{user} is not a domain')
|
||||||
|
|
||||||
|
followers = []
|
||||||
|
for follower in Follower.query(Follower.dest == user).fetch(limit):
|
||||||
|
actor = follower.to_as1()
|
||||||
|
print('@', actor)
|
||||||
|
if actor:
|
||||||
|
followers.append({
|
||||||
|
**bluesky.actor_to_ref(actor),
|
||||||
|
'$type': 'app.bsky.graph.getFollowers#follower',
|
||||||
|
'indexedAt': util.now().isoformat(),
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
'subject': bluesky.actor_to_ref({'url': f'https://{user}/'}),
|
||||||
|
'followers': followers,
|
||||||
|
'cursor': '',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@xrpc_server.method('app.bsky.graph.getFollows')
|
@xrpc_server.method('app.bsky.graph.getFollows')
|
||||||
def getFollows(input):
|
def getFollows(input, user=None, limit=None, before=None):
|
||||||
"""
|
"""
|
||||||
lexicons/app/bsky/graph/getFollows.json
|
lexicons/app/bsky/graph/getFollows.json
|
||||||
"""
|
"""
|
||||||
|
|
Ładowanie…
Reference in New Issue