noop, lint fixes from flake8

remaining:

$ flake8 --extend-ignore=E501 *.py tests/*.py
"pyflakes" failed during execution due to "'FlakesChecker' object has no attribute 'NAMEDEXPR'"
Run flake8 with greater verbosity to see more details
activitypub.py:15:1: F401 'oauth_dropins.webutil.util.json_loads' imported but unused
activitypub.py:36:1: F401 'web' imported but unused
activitypub.py:48:1: E302 expected 2 blank lines, found 1
activitypub.py:51:9: F811 redefinition of unused 'web' from line 36
app.py:6:1: F401 'flask_app.app' imported but unused
app.py:9:1: F401 'activitypub' imported but unused
app.py:9:1: F401 'convert' imported but unused
app.py:9:1: F401 'follow' imported but unused
app.py:9:1: F401 'pages' imported but unused
app.py:9:1: F401 'redirect' imported but unused
app.py:9:1: F401 'superfeedr' imported but unused
app.py:9:1: F401 'ui' imported but unused
app.py:9:1: F401 'webfinger' imported but unused
app.py:9:1: F401 'web' imported but unused
app.py:9:1: F401 'xrpc_actor' imported but unused
app.py:9:1: F401 'xrpc_feed' imported but unused
app.py:9:1: F401 'xrpc_graph' imported but unused
app.py:9:19: E401 multiple imports on one line
models.py:19:1: F401 'oauth_dropins.webutil.util.json_loads' imported but unused
models.py:364:31: E114 indentation is not a multiple of four (comment)
models.py:364:31: E116 unexpected indentation (comment)
protocol.py:17:1: F401 'oauth_dropins.webutil.util.json_loads' imported but unused
redirect.py:26:1: F401 'oauth_dropins.webutil.util.json_loads' imported but unused
web.py:18:1: F401 'oauth_dropins.webutil.util.json_loads' imported but unused
webfinger.py:13:1: F401 'oauth_dropins.webutil.util.json_loads' imported but unused
webfinger.py:110:13: E122 continuation line missing indentation or outdented
webfinger.py:111:13: E122 continuation line missing indentation or outdented
webfinger.py:131:13: E122 continuation line missing indentation or outdented
webfinger.py:132:13: E122 continuation line missing indentation or outdented
webfinger.py:133:13: E122 continuation line missing indentation or outdented
webfinger.py:134:13: E122 continuation line missing indentation or outdented
tests/__init__.py:2:1: F401 'oauth_dropins.webutil.tests' imported but unused
tests/test_follow.py:11:1: F401 'oauth_dropins.webutil.util.json_dumps' imported but unused
tests/test_follow.py:14:1: F401 '.testutil.Fake' imported but unused
tests/test_models.py:156:15: E122 continuation line missing indentation or outdented
tests/test_models.py:157:15: E122 continuation line missing indentation or outdented
tests/test_models.py:158:11: E122 continuation line missing indentation or outdented
tests/test_web.py:12:1: F401 'oauth_dropins.webutil.util.json_dumps' imported but unused
tests/test_web.py:17:1: F401 '.testutil' imported but unused
tests/test_web.py:1513:13: E128 continuation line under-indented for visual indent
tests/test_web.py:1514:9: E124 closing bracket does not match visual indentation
tests/testutil.py:106:1: E402 module level import not at top of file
tests/testutil.py:107:1: E402 module level import not at top of file
tests/testutil.py:108:1: E402 module level import not at top of file
tests/testutil.py:109:1: E402 module level import not at top of file
tests/testutil.py:110:1: E402 module level import not at top of file
tests/testutil.py:301:24: E203 whitespace before ':'
tests/testutil.py:301:25: E701 multiple statements on one line (colon)
tests/testutil.py:301:25: E231 missing whitespace after ':'
pull/561/head
Ryan Barrett 2023-06-20 11:22:54 -07:00
rodzic 2493e566ed
commit ab1c28ee4d
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
29 zmienionych plików z 158 dodań i 249 usunięć

Wyświetl plik

@ -28,7 +28,7 @@ from common import (
redirect_wrap,
TLD_BLOCKLIST,
)
from models import Follower, Object, PROTOCOLS, Target, User
from models import Follower, Object, PROTOCOLS, User
from protocol import Protocol
# TODO: remove this. we only need it to make sure Web is registered in PROTOCOLS
@ -263,8 +263,8 @@ class ActivityPub(User, Protocol):
key_actor = cls.load(keyId)
except BadGateway:
obj_id = as1.get_object(activity).get('id')
if (activity.get('type') == 'Delete' and obj_id and
keyId == fragmentless(obj_id)):
if (activity.get('type') == 'Delete' and obj_id
and keyId == fragmentless(obj_id)):
logger.info('Object/actor being deleted is also keyId')
key_actor = Object(id=keyId, source_protocol='activitypub', deleted=True)
key_actor.put()
@ -356,12 +356,13 @@ def signed_request(fn, url, data=None, log_data=True, headers=None, **kwargs):
# handle GET redirects manually so that we generate a new HTTP signature
if resp.is_redirect and fn == util.requests_get:
return signed_request(fn, resp.headers['Location'], data=data,
headers=headers, log_data=log_data, **kwargs)
return signed_request(fn, resp.headers['Location'], data=data,
headers=headers, log_data=log_data, **kwargs)
type = common.content_type(resp)
if (type and type != 'text/html' and
(type.startswith('text/') or type.endswith('+json') or type.endswith('/json'))):
(type.startswith('text/') or type.endswith('+json')
or type.endswith('/json'))):
logger.info(resp.text)
return resp
@ -546,7 +547,7 @@ def postprocess_as2_actor(actor, wrap=True):
url = g.user.web_url() if g.user else None
urls = util.get_list(actor, 'url')
if not urls and url:
urls = [url]
urls = [url]
domain = util.domain_from_link(urls[0], minimize=False)
if wrap:
@ -565,11 +566,11 @@ def postprocess_as2_actor(actor, wrap=True):
# Override the label for their home page to be "Web site"
for att in util.get_list(actor, 'attachment'):
if att.get('type') == 'PropertyValue':
val = att.get('value', '')
link = util.parse_html(val).find('a')
if url and (val == url or link.get('href') == url):
att['name'] = 'Web site'
if att.get('type') == 'PropertyValue':
val = att.get('value', '')
link = util.parse_html(val).find('a')
if url and (val == url or link.get('href') == url):
att['name'] = 'Web site'
# required by pixelfed. https://github.com/snarfed/bridgy-fed/issues/39
actor.setdefault('summary', '')
@ -591,7 +592,7 @@ def actor(protocol, domain):
if not g.user:
try:
obj = cls.load(f'https://{domain}/', gateway=True)
except NoMicroformats as e:
except NoMicroformats:
obj = None
g.user = cls.get_or_create(id=domain, obj=obj)

Wyświetl plik

@ -1,16 +1,19 @@
"""Bridgy App Engine config.
"""
# suppress these INFO logs:
# Sandbox prevented access to file "/usr/local/Caskroom/google-cloud-sdk"
# If it is a static file, check that `application_readable: true` is set in your app.yaml
import logging
class StubsFilter(logging.Filter):
def filter(self, record):
msg = record.getMessage()
if (msg.startswith('Sandbox prevented access to file') or
msg.startswith('If it is a static file, check that')):
return 0
return 1
"""Suppress these INFO logs:
Sandbox prevented access to file "/usr/local/Caskroom/google-cloud-sdk"
If it is a static file, check that `application_readable: true` is set in your app.yaml
"""
def filter(self, record):
msg = record.getMessage()
if (msg.startswith('Sandbox prevented access to file')
or msg.startswith('If it is a static file, check that')):
return 0
return 1
logging.getLogger().addFilter(StubsFilter())

Wyświetl plik

@ -2,7 +2,6 @@
"""Misc common utilities.
"""
import base64
import copy
from datetime import timedelta
import logging
import re
@ -12,11 +11,8 @@ import urllib.parse
import cachetools
from Crypto.Util import number
from flask import abort, g, make_response, request
from granary import as1, as2, microformats2
import mf2util
from oauth_dropins.webutil import util, webmention
from oauth_dropins.webutil.appengine_info import DEBUG
from oauth_dropins.webutil.util import json_dumps, json_loads
from werkzeug.exceptions import BadRequest
logger = logging.getLogger(__name__)
@ -90,10 +86,10 @@ def long_to_base64(x):
def host_url(path_query=None):
base = request.host_url
if (util.domain_or_parent_in(request.host, OTHER_DOMAINS) or
# when running locally against prod datastore
(not DEBUG and request.host in LOCAL_DOMAINS)):
base = f'https://{PRIMARY_DOMAIN}'
if (util.domain_or_parent_in(request.host, OTHER_DOMAINS)
# when running locally against prod datastore
or (not DEBUG and request.host in LOCAL_DOMAINS)):
base = f'https://{PRIMARY_DOMAIN}'
return urllib.parse.urljoin(base, path_query)
@ -105,26 +101,26 @@ def error(msg, status=400, exc_info=None, **kwargs):
def pretty_link(url, text=None, **kwargs):
"""Wrapper around util.pretty_link() that converts Mastodon user URLs to @-@.
"""Wrapper around util.pretty_link() that converts Mastodon user URLs to @-@.
Eg for URLs like https://mastodon.social/@foo and
https://mastodon.social/users/foo, defaults text to @foo@mastodon.social if
it's not provided.
Eg for URLs like https://mastodon.social/@foo and
https://mastodon.social/users/foo, defaults text to @foo@mastodon.social if
it's not provided.
Args:
url: str
text: str
kwargs: passed through to :func:`webutil.util.pretty_link`
"""
if g.user and g.user.is_web_url(url):
return g.user.user_page_link()
Args:
url: str
text: str
kwargs: passed through to :func:`webutil.util.pretty_link`
"""
if g.user and g.user.is_web_url(url):
return g.user.user_page_link()
if text is None:
match = re.match(r'https?://([^/]+)/(@|users/)([^/]+)$', url)
if match:
text = match.expand(r'@\3@\1')
if text is None:
match = re.match(r'https?://([^/]+)/(@|users/)([^/]+)$', url)
if match:
text = match.expand(r'@\3@\1')
return util.pretty_link(url, text=text, **kwargs)
return util.pretty_link(url, text=text, **kwargs)
def content_type(resp):
@ -199,25 +195,25 @@ def redirect_unwrap(val):
def webmention_endpoint_cache_key(url):
"""Returns cache key for a cached webmention endpoint for a given URL.
"""Returns cache key for a cached webmention endpoint for a given URL.
Just the domain by default. If the URL is the home page, ie path is / , the
key includes a / at the end, so that we cache webmention endpoints for home
pages separate from other pages. https://github.com/snarfed/bridgy/issues/701
Just the domain by default. If the URL is the home page, ie path is / , the
key includes a / at the end, so that we cache webmention endpoints for home
pages separate from other pages. https://github.com/snarfed/bridgy/issues/701
Example: 'snarfed.org /'
Example: 'snarfed.org /'
https://github.com/snarfed/bridgy-fed/issues/423
https://github.com/snarfed/bridgy-fed/issues/423
Adapted from bridgy/util.py.
"""
parsed = urllib.parse.urlparse(url)
key = parsed.netloc
if parsed.path in ('', '/'):
key += ' /'
Adapted from bridgy/util.py.
"""
parsed = urllib.parse.urlparse(url)
key = parsed.netloc
if parsed.path in ('', '/'):
key += ' /'
# logger.debug(f'wm cache key {key}')
return key
# logger.debug(f'wm cache key {key}')
return key
@cachetools.cached(cachetools.TTLCache(50000, 60 * 60 * 2), # 2h expiration

Wyświetl plik

@ -14,10 +14,10 @@ SESSION_COOKIE_SAMESITE = 'Lax'
CACHE_THRESHOLD = 3000
if appengine_info.DEBUG:
ENV = 'development'
CACHE_TYPE = 'NullCache'
SECRET_KEY = 'sooper seekret'
ENV = 'development'
CACHE_TYPE = 'NullCache'
SECRET_KEY = 'sooper seekret'
else:
ENV = 'production'
CACHE_TYPE = 'SimpleCache'
SECRET_KEY = util.read('flask_secret_key')
ENV = 'production'
CACHE_TYPE = 'SimpleCache'
SECRET_KEY = util.read('flask_secret_key')

Wyświetl plik

@ -5,7 +5,6 @@ constants from the :class:`Protocol` subclasses.
"""
import logging
import re
import urllib.parse
from flask import g, redirect, request
from granary import as1
@ -78,8 +77,8 @@ def convert(dest, _):
if obj_id:
# TODO: PROTOCOLS[src].load() this instead?
obj_obj = Object.get_by_id(obj_id)
if (obj_obj and obj_obj.as1 and
not obj_obj.as1.keys() <= set(['id', 'url', 'objectType'])):
if (obj_obj and obj_obj.as1
and not obj_obj.as1.keys() <= set(['id', 'url', 'objectType'])):
logger.info(f'{type} activity, redirecting to Object {obj_id}')
return redirect(f'/{path_prefix}{obj_id}', code=301)

Wyświetl plik

@ -15,8 +15,6 @@ from oauth_dropins.webutil import (
util,
)
import common
logger = logging.getLogger(__name__)
logging.getLogger('lexrpc').setLevel(logging.INFO)
logging.getLogger('negotiator').setLevel(logging.WARNING)
@ -34,6 +32,7 @@ app.register_error_handler(Exception, flask_util.handle_exception)
if appengine_info.LOCAL:
flask_gae_static.init_app(app)
@app.before_request
def init_globals():
"""Set request globals.
@ -42,6 +41,7 @@ def init_globals():
"""
g.user = None
# don't redirect API requests with blank path elements
app.url_map.merge_slashes = False
app.url_map.redirect_defaults = False

Wyświetl plik

@ -5,16 +5,13 @@ https://socialhub.activitypub.rocks/t/what-is-the-current-spec-for-remote-follow
https://www.rfc-editor.org/rfc/rfc7033
"""
import logging
import urllib.parse
from flask import g, redirect, request, session
from granary import as2
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.flask_util import error, flash
from oauth_dropins.webutil.testutil import NOW
from oauth_dropins.webutil.util import json_dumps, json_loads
from activitypub import ActivityPub
from flask_app import app

Wyświetl plik

@ -7,7 +7,6 @@ import random
import urllib.parse
from arroba.mst import dag_cbor_cid
from Crypto import Random
from Crypto.PublicKey import ECC, RSA
import dag_json
from flask import g, request
@ -18,10 +17,9 @@ from oauth_dropins.webutil.appengine_info import DEBUG
from oauth_dropins.webutil.flask_util import error
from oauth_dropins.webutil.models import ComputedJsonProperty, JsonProperty, StringIdModel
from oauth_dropins.webutil.util import json_dumps, json_loads
import requests
import common
from common import base64_to_long, long_to_base64, redirect_unwrap, redirect_wrap
from common import base64_to_long, long_to_base64, redirect_unwrap
# maps string label to Protocol subclass. populated by ProtocolUserMeta.
# seed with old and upcoming protocols that don't have their own classes (yet).
@ -475,8 +473,8 @@ class Object(StringIdModel):
"""Returns a pretty actor link with their name and profile picture."""
attrs = {'class': 'h-card u-author'}
if (self.source_protocol in ('web', 'webmention', 'ui') and g.user and
(g.user.key in self.users or g.user.key.id() in self.domains)):
if (self.source_protocol in ('web', 'webmention', 'ui') and g.user
and (g.user.key in self.users or g.user.key.id() in self.domains)):
# outbound; show a nice link to the user
return g.user.user_page_link()
@ -498,6 +496,7 @@ class Object(StringIdModel):
{util.ellipsize(name, chars=40)}
</a>"""
class AtpNode(StringIdModel):
"""An AT Protocol (Bluesky) node.

Wyświetl plik

@ -1,26 +1,20 @@
"""UI pages."""
import calendar
import datetime
import logging
import os
import re
import urllib.parse
from flask import g, redirect, render_template, request
from google.cloud.ndb.model import get_multi
from flask import g, render_template, request
from google.cloud.ndb.query import OR
from google.cloud.ndb.stats import KindStat
from granary import as1, as2, atom, microformats2, rss
import humanize
from oauth_dropins.webutil import flask_util, logs, util
from oauth_dropins.webutil.flask_util import error, flash, redirect
from oauth_dropins.webutil.util import json_dumps, json_loads
from oauth_dropins.webutil.flask_util import error, redirect
import common
from common import DOMAIN_RE
from flask_app import app, cache
from models import fetch_page, Follower, Object, PAGE_SIZE, PROTOCOLS, User
from web import Web
from models import fetch_page, Follower, Object, PAGE_SIZE, PROTOCOLS
FOLLOWERS_UI_LIMIT = 999
@ -192,7 +186,6 @@ def fetch_objects(query):
to fetch the previous and next pages, respectively
"""
objects, new_before, new_after = fetch_page(query, Object)
seen = set()
# synthesize human-friendly content for objects
for i, obj in enumerate(objects):

Wyświetl plik

@ -3,18 +3,17 @@ import logging
import threading
from urllib.parse import urljoin
from cachetools import cached, LRUCache
from cachetools import LRUCache
from flask import g, request
from google.cloud import ndb
from google.cloud.ndb import OR
from granary import as1, as2
import requests
from granary import as1
import werkzeug.exceptions
import common
from common import error
from models import Follower, Object, PROTOCOLS, Target
from oauth_dropins.webutil import util, webmention
from oauth_dropins.webutil import util
from oauth_dropins.webutil.util import json_dumps, json_loads
SUPPORTED_TYPES = (
@ -433,8 +432,8 @@ class Protocol:
# deliver original posts and reposts to followers
is_reply = (obj.type == 'comment' or
(inner_obj and inner_obj.get('inReplyTo')))
if (actor and actor_id and
(obj.type == 'share' or obj.type in ('create', 'post') and not is_reply)):
if ((obj.type == 'share' or obj.type in ('create', 'post') and not is_reply)
and actor and actor_id):
logger.info(f'Delivering to followers of {actor_id}')
for f in Follower.query(Follower.to == from_cls(id=actor_id).key,
Follower.status == 'active'):
@ -580,11 +579,11 @@ class Protocol:
if 'notification' not in obj.labels:
obj.labels.append('notification')
except BaseException as e:
code, body = util.interpret_http_exception(e)
if not code and not body:
raise
errors.append((code, body))
obj.failed.append(target)
code, body = util.interpret_http_exception(e)
if not code and not body:
raise
errors.append((code, body))
obj.failed.append(target)
obj.put()

Wyświetl plik

@ -18,7 +18,7 @@ import logging
import re
import urllib.parse
from flask import g, redirect, request
from flask import g, request
from granary import as2
from negotiator import ContentNegotiator, AcceptParameters, ContentType
from oauth_dropins.webutil import flask_util, util
@ -28,7 +28,6 @@ from oauth_dropins.webutil.util import json_dumps, json_loads
from activitypub import ActivityPub
from flask_app import app, cache
from common import CACHE_TIME, CONTENT_TYPE_HTML
from models import Object, User
from web import Web
logger = logging.getLogger(__name__)

Wyświetl plik

@ -6,14 +6,12 @@ from datetime import datetime, timedelta
from hashlib import sha256
import logging
from unittest import skip
from unittest.mock import ANY, call, patch
import urllib.parse
from unittest.mock import patch
from flask import g
from google.cloud import ndb
from granary import as2, microformats2
from httpsig import HeaderSigner
from oauth_dropins.webutil import util
from oauth_dropins.webutil.testutil import requests_response
from oauth_dropins.webutil.util import json_dumps, json_loads
import requests
@ -26,10 +24,8 @@ from .testutil import Fake, TestCase
import activitypub
from activitypub import ActivityPub, postprocess_as2
import common
import models
from models import Follower, Object
import protocol
from protocol import Protocol
from web import Web
# have to import module, not attrs, to avoid circular import
@ -49,7 +45,7 @@ ACTOR_BASE = {
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
],
'type' : 'Person',
'type': 'Person',
'id': 'http://localhost/user.com',
'url': 'http://localhost/r/https://user.com/',
'preferredUsername': 'user.com',
@ -387,7 +383,7 @@ class ActivityPubTest(TestCase):
**REPLY,
'actor': LIKE_ACTOR,
}
got = self._test_inbox_reply(reply, {
self._test_inbox_reply(reply, {
'as2': reply,
'type': 'post',
'labels': ['activity', 'notification'],
@ -749,7 +745,6 @@ class ActivityPubTest(TestCase):
self.assert_user(ActivityPub, 'https://user.com/actor',
obj_as2=LIKE_ACTOR, direct=True)
def test_inbox_follow_accept_with_id(self, *mocks):
self._test_inbox_follow_accept(FOLLOW_WRAPPED, ACCEPT, *mocks)
@ -768,10 +763,6 @@ class ActivityPubTest(TestCase):
object_ids=[FOLLOW['object']])
def test_inbox_follow_accept_with_object(self, *mocks):
wrapped_user = {
'id': FOLLOW_WRAPPED['object'],
'url': FOLLOW_WRAPPED['object'],
}
unwrapped_user = {
'id': FOLLOW['object'],
'url': FOLLOW['object'],
@ -905,7 +896,6 @@ class ActivityPubTest(TestCase):
self.assertEqual('https://mas.to/users/swentel#followed-https://user.com/',
follower.follow.get().as2['url'])
def test_inbox_undo_follow(self, mock_head, mock_get, mock_post):
follower = Follower(to=self.user.key,
from_=ActivityPub.get_or_create(ACTOR['id']).key,
@ -1065,7 +1055,6 @@ class ActivityPubTest(TestCase):
# invalid signature, header changed
protocol.seen_ids.clear()
obj_key.delete()
orig_date = headers['Date']
resp = self.client.post('/ap/sharedInbox', data=body, headers={**headers, 'Date': 'X'})
self.assertEqual(401, resp.status_code)
@ -1505,7 +1494,7 @@ class ActivityPubUtilsTest(TestCase):
}, postprocess_as2({
'tag': [
{'name': 'bar', 'href': 'bar'},
{'type': 'Tag','name': '#baz'},
{'type': 'Tag', 'name': '#baz'},
# should leave alone
{'type': 'Mention', 'href': 'foo'},
],
@ -1644,7 +1633,7 @@ class ActivityPubUtilsTest(TestCase):
allow_redirects=False),
requests_response(status=200, allow_redirects=False),
]
resp = activitypub.signed_get('https://first')
activitypub.signed_get('https://first')
first = mock_get.call_args_list[0][1]
second = mock_get.call_args_list[1][1]
@ -1697,7 +1686,7 @@ class ActivityPubUtilsTest(TestCase):
mock_get.assert_has_calls((
self.as2_req('http://orig'),
self.as2_req('http://as2', headers=common.as2.CONNEG_HEADERS),
self.as2_req('http://as2', headers=as2.CONNEG_HEADERS),
))
@patch('requests.get')
@ -1708,7 +1697,7 @@ class ActivityPubUtilsTest(TestCase):
@patch('requests.get')
def test_fetch_not_acceptable(self, mock_get):
mock_get.return_value=NOT_ACCEPTABLE
mock_get.return_value = NOT_ACCEPTABLE
with self.assertRaises(BadGateway):
ActivityPub.fetch(Object(id='http://orig'))

Wyświetl plik

@ -1,19 +1,11 @@
"""Unit tests for common.py."""
from unittest import mock
from flask import g
from granary import as2
from oauth_dropins.webutil import appengine_config, util
from oauth_dropins.webutil.testutil import requests_response
import requests
# import first so that Fake is defined before URL routes are registered
from .testutil import Fake, TestCase
import common
from flask_app import app
from models import Object, User
import protocol
from web import Web

Wyświetl plik

@ -8,7 +8,6 @@ from granary.tests.test_as1 import ACTOR, COMMENT, DELETE_OF_ID, UPDATE
from models import Object
from oauth_dropins.webutil.testutil import requests_response
from oauth_dropins.webutil.util import parse_mf2
import requests
# import first so that Fake is defined before URL routes are registered
from . import testutil
@ -191,7 +190,7 @@ class ConvertTest(testutil.TestCase):
resp.headers['Location'])
def test_activitypub_to_web_update_no_inner_obj_serve_as_is(self):
# UPDATE's object field is a full object
# Update's object field is a full object
Object(id='http://foo', our_as1=UPDATE).put()
resp = self.client.get('/convert/web/http://foo',
@ -205,7 +204,7 @@ A ☕ reply
""", resp.get_data(as_text=True), ignore_blanks=True)
def test_activitypub_to_web_update_inner_obj_too_minimal_serve_as_is(self):
# UPDATE's object field is a full object
# Update's object field is a full object
Object(id='http://foo', our_as1=UPDATE).put()
Object(id=UPDATE['object']['id'], as2={'id': 'foo'}).put()
@ -259,4 +258,3 @@ A ☕ reply
resp = self.client.get(f'/convert/ap/http://nope.com/post',
base_url='https://ap.brid.gy/')
self.assertEqual(400, resp.status_code)

Wyświetl plik

@ -14,10 +14,7 @@ from oauth_dropins.webutil.util import json_dumps, json_loads
from .testutil import Fake, TestCase
from activitypub import ActivityPub
import common
from common import redirect_unwrap
from models import Follower, Object, User
from web import Web
from models import Follower, Object
WEBFINGER = requests_response({
'subject': 'acct:foo@bar',
@ -191,7 +188,7 @@ class FollowTest(TestCase):
def check(self, input, resp, expected_follow, mock_get, mock_post):
self.assertEqual(302, resp.status_code)
self.assertEqual('/web/alice.com/following',resp.headers['Location'])
self.assertEqual('/web/alice.com/following', resp.headers['Location'])
self.assertEqual([f'Followed <a href="https://bar/url">{input}</a>.'],
get_flashed_messages())

Wyświetl plik

@ -1,20 +1,15 @@
# coding=utf-8
"""Unit tests for models.py."""
from unittest import mock
from arroba.mst import dag_cbor_cid
from Crypto.PublicKey import ECC
from flask import g, get_flashed_messages
from granary import as2
from flask import g
from granary.tests.test_bluesky import ACTOR_PROFILE_BSKY
from multiformats import CID
from oauth_dropins.webutil.testutil import NOW, requests_response
from oauth_dropins.webutil.testutil import NOW
# import first so that Fake is defined before URL routes are registered
from .testutil import Fake, TestCase
import common
from models import AtpNode, Follower, Object, OBJECT_EXPIRE_AGE, User
from models import AtpNode, Follower, Object, OBJECT_EXPIRE_AGE
import protocol
from web import Web
@ -158,9 +153,9 @@ class ObjectTest(TestCase):
title="Alice">
<img class="profile" src="http://pic/" />
Alice""", {'actor': {
'name': 'Alice',
'icon': {'type': 'Image', 'url': 'http://pic'},
}}),
'name': 'Alice',
'icon': {'type': 'Image', 'url': 'http://pic'},
}}),
):
obj = Object(id='x', as2=as2)
self.assert_multiline_in(expected, obj.actor_link())

Wyświetl plik

@ -1,32 +1,26 @@
"""Unit tests for pages.py."""
from granary import as2, atom, microformats2, rss
from granary.tests.test_bluesky import REPLY_BSKY
from granary import atom, microformats2, rss
from granary.tests.test_as1 import (
ACTOR,
COMMENT,
FOLLOW_WITH_ACTOR,
FOLLOW_WITH_OBJECT,
LIKE,
NOTE,
)
from oauth_dropins.webutil import util
from oauth_dropins.webutil.testutil import requests_response
# import first so that Fake is defined before URL routes are registered
from .testutil import Fake, TestCase
from activitypub import ActivityPub
import common
from models import Object, Follower, User
from web import Web
from models import Object, Follower
from .test_web import ACTOR_AS2, ACTOR_HTML, ACTOR_MF2, REPOST_AS2
from .test_web import ACTOR_AS2, REPOST_AS2
ACTOR_WITH_PREFERRED_USERNAME = {
**ACTOR,
'preferredUsername': 'me',
}
def contents(activities):
return [(a.get('object') or a)['content'] for a in activities]

Wyświetl plik

@ -13,7 +13,6 @@ from app import app
from models import Follower, Object, PROTOCOLS, User
import protocol
from protocol import Protocol
import requests
from ui import UIProtocol
from web import Web

Wyświetl plik

@ -5,20 +5,17 @@ from unittest.mock import patch
from granary import as2
from oauth_dropins.webutil.testutil import requests_response
import requests
# import first so that Fake is defined before URL routes are registered
from . import testutil
from common import redirect_unwrap
from flask_app import app, cache
from models import Object, User
from models import Object
from web import Web
from .test_activitypub import ACTOR_BASE_FULL
from .test_web import (
ACTOR_AS2,
ACTOR_AS2_FULL,
ACTOR_HTML,
REPOST_AS2,
REPOST_HTML,
@ -146,7 +143,7 @@ class RedirectTest(testutil.TestCase):
self._test_as2(as2.CONTENT_TYPE)
resp = self.client.get('/r/https://user.com/bar',
headers={'Accept': 'text/html'})
headers={'Accept': 'text/html'})
self.assertEqual(301, resp.status_code)
self.assertEqual('https://user.com/bar', resp.headers['Location'])
@ -162,5 +159,5 @@ class RedirectTest(testutil.TestCase):
Object(id='https://user.com/bar', as2={}, deleted=True).put()
resp = self.client.get('/r/https://user.com/bar',
headers={'Accept': as2.CONTENT_TYPE})
headers={'Accept': as2.CONTENT_TYPE})
self.assertEqual(404, resp.status_code, resp.get_data(as_text=True))

Wyświetl plik

@ -4,28 +4,21 @@ import copy
from unittest.mock import patch
from urllib.parse import urlencode
import feedparser
from flask import g, get_flashed_messages
from granary import as1, as2, atom, microformats2
from httpsig.sign import HeaderSigner
from oauth_dropins.webutil import appengine_config, util
from oauth_dropins.webutil.appengine_config import tasks_client
from granary import as1, as2, microformats2
from oauth_dropins.webutil import util
from oauth_dropins.webutil.appengine_info import APP_ID
from oauth_dropins.webutil.testutil import NOW, requests_response
from oauth_dropins.webutil.util import json_dumps, json_loads
import requests
from requests import HTTPError
from werkzeug.exceptions import BadGateway, BadRequest
# import first so that Fake is defined before URL routes are registered
from . import testutil
from activitypub import ActivityPub, postprocess_as2
from common import (
CONTENT_TYPE_HTML,
redirect_unwrap,
)
from models import Follower, Object, Target, User
from common import CONTENT_TYPE_HTML
from models import Follower, Object
from web import TASKS_LOCATION, Web
from . import test_activitypub
from .testutil import TestCase
@ -210,7 +203,7 @@ REPLY_HTML = """\
</html>
"""
REPLY = requests_response(REPLY_HTML, content_type=CONTENT_TYPE_HTML,
url='https://user.com/reply')
url='https://user.com/reply')
REPLY_MF2 = util.parse_mf2(REPLY_HTML)['items'][0]
REPLY_AS1 = microformats2.json_to_object(REPLY_MF2)
CREATE_REPLY_AS1 = {
@ -238,7 +231,7 @@ LIKE = requests_response(LIKE_HTML, content_type=CONTENT_TYPE_HTML,
LIKE_MF2 = util.parse_mf2(LIKE_HTML)['items'][0]
ACTOR = TestCase.as2_resp({
'type' : 'Person',
'type': 'Person',
'name': 'Mrs. ☕ Foo',
'id': 'https://mas.to/mrs-foo',
'inbox': 'https://mas.to/inbox',
@ -583,9 +576,6 @@ class WebTest(TestCase):
self.assertEqual(502, got.status_code)
def test_target_fetch_has_no_content_type(self, mock_get, mock_post):
html = REPLY_HTML.replace(
'</body>',
"<link href='http://as2' rel='alternate' type='application/activity+json'></body")
mock_get.side_effect = (
requests_response(REPLY_HTML, url='https://user.com/reply'),
requests_response(REPLY_HTML, url='https://user.com/reply',
@ -612,7 +602,7 @@ class WebTest(TestCase):
def test_backlink_without_trailing_slash(self, mock_get, mock_post):
mock_get.return_value = requests_response(
REPLY_HTML.replace('<a href="http://localhost/"></a>',
'<a href="http://localhost"></a>'),
'<a href="http://localhost"></a>'),
content_type=CONTENT_TYPE_HTML, url='https://user.com/reply')
got = self.client.post('/_ah/queue/webmention', data={
@ -1148,17 +1138,17 @@ class WebTest(TestCase):
self.assert_deliveries(mock_post, ['https://mas.to/inbox'],
FOLLOW_FRAGMENT_AS2)
obj = self.assert_object('https://user.com/follow#2',
users=[g.user.key],
source_protocol='web',
status='complete',
mf2=FOLLOW_FRAGMENT_MF2,
as1=FOLLOW_FRAGMENT_AS1,
delivered=['https://mas.to/inbox'],
type='follow',
object_ids=['https://mas.to/mrs-foo'],
labels=['user', 'activity'],
)
self.assert_object('https://user.com/follow#2',
users=[g.user.key],
source_protocol='web',
status='complete',
mf2=FOLLOW_FRAGMENT_MF2,
as1=FOLLOW_FRAGMENT_AS1,
delivered=['https://mas.to/inbox'],
type='follow',
object_ids=['https://mas.to/mrs-foo'],
labels=['user', 'activity'],
)
followers = Follower.query().fetch()
self.assert_equals(1, len(followers))
@ -1178,7 +1168,7 @@ class WebTest(TestCase):
content_type=CONTENT_TYPE_HTML),
ACTOR,
self.as2_resp({
'objectType' : 'Person',
'objectType': 'Person',
'displayName': 'Mr. ☕ Biff',
'id': 'https://mas.to/mr-biff',
'inbox': 'https://mas.to/inbox/biff',
@ -1277,7 +1267,7 @@ class WebTest(TestCase):
type='delete',
object_ids=['https://user.com/post'],
labels=['user', 'activity'],
)
)
def test_delete_no_object(self, mock_get, mock_post):
mock_get.side_effect = [
@ -1336,7 +1326,7 @@ class WebTest(TestCase):
type='follow',
object_ids=['https://mas.to/mrs-foo'],
labels=['user', 'activity'],
)
)
def test_repost_blocklisted_error(self, mock_get, mock_post):
"""Reposts of non-fediverse (ie blocklisted) sites aren't yet supported."""
@ -1723,7 +1713,7 @@ class WebProtocolTest(TestCase):
self.assert_equals({**REPOST_MF2, 'url': 'https://user.com/repost'}, obj.mf2)
def test_fetch_redirect(self, mock_get, __):
mock_get.return_value =requests_response(
mock_get.return_value = requests_response(
REPOST_HTML, content_type=CONTENT_TYPE_HTML,
redirected_url='http://new/url')
obj = Object(id='https://orig/url')
@ -1735,7 +1725,7 @@ class WebProtocolTest(TestCase):
def test_fetch_error(self, mock_get, __):
mock_get.return_value = requests_response(REPOST_HTML, status=405)
with self.assertRaises(BadGateway) as e:
with self.assertRaises(BadGateway):
Web.fetch(Object(id='https://foo'), gateway=True)
def test_fetch_run_authorship(self, mock_get, __):

Wyświetl plik

@ -1,7 +1,6 @@
# coding=utf-8
"""Unit tests for webfinger.py."""
import copy
import html
from unittest.mock import patch
import urllib.parse
@ -10,7 +9,6 @@ from oauth_dropins.webutil.testutil import requests_response
# import first so that Fake is defined before URL routes are registered
from .testutil import Fake, TestCase
import common
from web import Web
from .test_web import ACTOR_HTML
@ -115,7 +113,7 @@ class HostMetaTest(TestCase):
got = self.client.get('/.well-known/host-meta')
self.assertEqual(200, got.status_code)
self.assertEqual('application/xrd+xml; charset=utf-8',
got.headers['Content-Type'])
got.headers['Content-Type'])
body = got.get_data(as_text=True)
self.assertTrue(body.startswith('<?xml'), body)

Wyświetl plik

@ -1,13 +1,9 @@
"""Unit tests for actor.py."""
from oauth_dropins.webutil import util
from oauth_dropins.webutil.testutil import requests_response
import requests
from unittest import skip
# import first so that Fake is defined before URL routes are registered
from . import testutil
from models import User
from .test_activitypub import ACTOR
@ -30,7 +26,6 @@ class XrpcActorTest(testutil.TestCase):
'handle': 'mas.to/users/swentel',
'did': 'did:web:mas.to:users:swentel',
'displayName': 'Mrs. ☕ Foo',
'description': None,
'description': "I'm a person",
'avatar': 'https://user.com/me.jpg',
'banner': 'http://user.com/header.png',
@ -59,7 +54,7 @@ class XrpcActorTest(testutil.TestCase):
def test_search(self):
resp = self.client.get('/xrpc/app.bsky.actor.searchActors',
query_string={'term': 'foo'})
query_string={'term': 'foo'})
self.assertEqual(200, resp.status_code)
self.assertEqual({
'actors': [],
@ -67,7 +62,7 @@ class XrpcActorTest(testutil.TestCase):
def test_searchTypeahead(self):
resp = self.client.get('/xrpc/app.bsky.actor.searchActorsTypeahead',
query_string={'term': 'foo'})
query_string={'term': 'foo'})
self.assertEqual(200, resp.status_code)
self.assertEqual({
'actors': [],

Wyświetl plik

@ -1,5 +1,4 @@
"""Unit tests for feed.py."""
import copy
from unittest import skip
from granary import as2, bluesky
@ -7,22 +6,15 @@ from granary.tests.test_as1 import COMMENT, NOTE
from granary.tests.test_bluesky import (
POST_BSKY,
POST_AS,
POST_AUTHOR_AS,
REPLY_BSKY,
REPLY_AS,
REPOST_BSKY,
REPOST_AS,
)
from oauth_dropins.webutil import util
from oauth_dropins.webutil.testutil import requests_response
import requests
from werkzeug.exceptions import BadGateway
# import first so that Fake is defined before URL routes are registered
from . import testutil
import common
from models import Object, User
from models import Object
from .test_activitypub import ACTOR
POST_THREAD_AS = {
@ -90,7 +82,7 @@ class XrpcFeedTest(testutil.TestCase):
Object(id='d', domains=['user.com'], labels=['feed'], as2=post_as2).put()
# deleted
Object(id='e', domains=['user.com'], labels=['user'], as2=post_as2,
deleted=True).put()
deleted=True).put()
# other user's
Object(id='f', domains=['bar.org'], labels=['user'], as2=post_as2).put()
@ -151,7 +143,7 @@ class XrpcFeedTest(testutil.TestCase):
})).put()
got = self.client.get('/xrpc/app.bsky.feed.getRepostedBy',
query_string={'uri': 'http://a/post'})
query_string={'uri': 'http://a/post'})
self.assertEqual({
'uri': 'http://orig/post',
'repostBy': [{

Wyświetl plik

@ -1,13 +1,9 @@
"""Unit tests for graph.py."""
from granary import bluesky
from oauth_dropins.webutil.testutil import requests_response
import requests
# import first so that Fake is defined before URL routes are registered
from . import testutil
from .test_activitypub import ACTOR, FOLLOW, FOLLOW_WITH_ACTOR, FOLLOW_WITH_OBJECT
from models import Follower, User
from .test_activitypub import FOLLOW, FOLLOW_WITH_ACTOR, FOLLOW_WITH_OBJECT
from models import Follower
from unittest import skip
SUBJECT = {
@ -42,19 +38,19 @@ class XrpcGraphTest(testutil.TestCase):
def test_getFollowers_not_domain(self):
resp = self.client.get('/xrpc/app.bsky.graph.getFollowers',
query_string={'user': 'not a domain'})
query_string={'user': 'not a domain'})
self.assertEqual(400, resp.status_code)
def test_getFollowers_no_user(self):
resp = self.client.get('/xrpc/app.bsky.graph.getFollowers',
query_string={'user': 'no.com'})
query_string={'user': 'no.com'})
self.assertEqual(400, resp.status_code)
def test_getFollowers_empty(self):
self.make_user('user.com')
resp = self.client.get('/xrpc/app.bsky.graph.getFollowers',
query_string={'user': 'user.com'})
query_string={'user': 'user.com'})
self.assertEqual(200, resp.status_code)
self.assertEqual({
'subject': SUBJECT,
@ -83,7 +79,7 @@ class XrpcGraphTest(testutil.TestCase):
last_follow=other_follow)
resp = self.client.get('/xrpc/app.bsky.graph.getFollowers',
query_string={'user': 'user.com'})
query_string={'user': 'user.com'})
self.assertEqual(200, resp.status_code)
self.assertEqual({
'subject': SUBJECT,
@ -93,14 +89,14 @@ class XrpcGraphTest(testutil.TestCase):
def test_getFollows_not_domain(self):
resp = self.client.get('/xrpc/app.bsky.graph.getFollows',
query_string={'user': 'not a domain'})
query_string={'user': 'not a domain'})
self.assertEqual(400, resp.status_code)
def test_getFollows_empty(self):
self.make_user('user.com')
resp = self.client.get('/xrpc/app.bsky.graph.getFollows',
query_string={'user': 'user.com'})
query_string={'user': 'user.com'})
self.assertEqual(200, resp.status_code)
self.assertEqual({
'subject': SUBJECT,
@ -123,13 +119,13 @@ class XrpcGraphTest(testutil.TestCase):
Follower.get_or_create('https://no/stored/follow', 'user.com')
Follower.get_or_create('https://masto/user', 'user.com',
last_follow=FOLLOW_WITH_OBJECT)
Follower.get_or_create( 'http://other', 'user.com',
Follower.get_or_create('http://other', 'user.com',
last_follow=other_follow)
Follower.get_or_create('http://nope', 'nope.com',
last_follow=other_follow)
resp = self.client.get('/xrpc/app.bsky.graph.getFollows',
query_string={'user': 'user.com'})
query_string={'user': 'user.com'})
self.assertEqual(200, resp.status_code)
self.assertEqual({
'subject': SUBJECT,

4
web.py
Wyświetl plik

@ -6,11 +6,9 @@ import re
import urllib.parse
from urllib.parse import urlencode, urljoin, urlparse
import feedparser
from flask import g, redirect, render_template, request
from flask.views import View
from google.cloud import ndb
from google.cloud.ndb import ComputedProperty, Key
from google.cloud.ndb import ComputedProperty
from granary import as1, as2, microformats2
import mf2util
from oauth_dropins.webutil import flask_util, util

Wyświetl plik

@ -3,9 +3,7 @@
https://webfinger.net/
https://tools.ietf.org/html/rfc7033
"""
import datetime
import logging
import re
import urllib.parse
from flask import g, render_template, request
@ -16,7 +14,6 @@ from oauth_dropins.webutil.util import json_dumps, json_loads
import common
from flask_app import app, cache
from models import User
from protocol import Protocol
from web import Web
@ -56,7 +53,7 @@ class Webfinger(flask_util.XrdOrJrd):
cls = Protocol.for_domain(id, fed=Web)
if cls:
id = user
allow_indirect=True
allow_indirect = True
except ValueError:
id = urllib.parse.urlparse(resource).netloc or resource

Wyświetl plik

@ -4,12 +4,10 @@ import json
import re
from flask import g
from granary import microformats2, bluesky
import mf2util
from granary import bluesky
from oauth_dropins.webutil import util
from flask_app import xrpc_server
from models import User
from web import Web
logger = logging.getLogger(__name__)

Wyświetl plik

@ -4,12 +4,11 @@ import logging
import re
from flask import g
from granary import bluesky, microformats2
import mf2util
from granary import bluesky
from oauth_dropins.webutil import util
from flask_app import xrpc_server
from models import Object, PAGE_SIZE, User
from models import Object, PAGE_SIZE
from web import Web
logger = logging.getLogger(__name__)

Wyświetl plik

@ -6,8 +6,7 @@ from granary import bluesky
from oauth_dropins.webutil import util
from flask_app import xrpc_server
import common
from models import Follower, User
from models import Follower
from web import Web
logger = logging.getLogger(__name__)