Verified Commit cb55f756 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Basic logic to extract provider data from URLs

parent 75f93916
import re
class Registry(object):
def __init__(self):
self._data = {}
def register(self, obj):
if not
raise ValueError("{} has no id".format(
self._data[] = obj()
def __iter__(self):
yield from self._data.items()
registry = Registry()
class Provider(object):
id = None
domains = []
username_regex = None
class BasicUsernameProvider(Provider):
username_regex = r"^\/([\w\.]+)/?$"
def match_from_url(self, parsed_url):
if not and not self.username_regex:
if parsed_url.hostname not in
compiled = re.compile(self.username_regex)
result = compiled.match(parsed_url.path)
if not result:
username = result.groups()[0]
return {"provider":, "id": username}
class Patreon(BasicUsernameProvider):
id = "patreon"
domains = [""]
class Liberapay(BasicUsernameProvider):
id = "liberapay"
domains = [""]
class KoFi(BasicUsernameProvider):
id = "ko-fi"
domains = [""]
import urllib.parse
from retribute_api import providers
def extract_from_url(url):
parsed = urllib.parse.urlparse(url)
for id, provider in providers.registry:
result = provider.match_from_url(parsed)
if result:
return result
return None
from rest_framework import serializers
async def lookup(name, session):
username, domain = name.split("@")
response = await session.get(
params={"resource": "acct:{}".format(name)},
return await response.json()
class AccountLinkSerializer(serializers.Serializer):
rel = serializers.CharField()
href = serializers.URLField()
type = serializers.CharField()
class WebfingerSerializer(serializers.Serializer):
links = serializers.ListField(child=AccountLinkSerializer(), min_length=1)
def get_links(payload):
serializer = WebfingerSerializer(data=payload)
links = {}
for link in serializer.validated_data["links"]:
if link["rel"] != "self":
if link["type"] == "application/activity+json":
links["activitypub"] = link["href"]
return links
......@@ -65,6 +65,7 @@ universal = 1
testpaths = tests
env =
import pytest
import aiohttp
from aioresponses import aioresponses
import asynctest
pytest_plugins = "aiohttp.pytest_plugin"
def responses():
with aioresponses() as m:
yield m
async def session(loop):
async with aiohttp.ClientSession() as session:
yield session
async def coroutine_mock():
return asynctest.CoroutineMock
import pytest
from import means
"input, expected",
("", {"provider": "patreon", "id": "username"}),
("", {"provider": "liberapay", "id": "username"}),
("", {"provider": "ko-fi", "id": "username"}),
("", None),
def test_extract_from_url(input, expected):
assert means.extract_from_url(input) == expected
from import webfinger
async def test_wellknown_success(responses, session):
name = "user@domain.test"
webfinger_response = {
"subject": "acct:user@domain.test",
"aliases": ["https://domain.test/@user", "https://domain.test/users/user"],
"links": [
"rel": "self",
"type": "application/activity+json",
"href": "https://domain.test/users/user",
response = await webfinger.lookup(name, session)
assert response == webfinger_response
def test_get_links(settings):
payload = {
"links": [
"rel": "self",
"type": "application/activity+json",
"href": "https://domain.test/users/user",
expected = {"activitypub": "https://domain.test/users/user"}
assert webfinger.get_links(payload) == expected
def test_something():
assert 1 == 2
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment