Can now fetch domain nodeinfo

This commit is contained in:
Eliot Berriot 2018-12-27 17:42:43 +01:00
parent e4117043cb
commit be388870a3
No known key found for this signature in database
GPG key ID: DD6965E2476E5C27
9 changed files with 171 additions and 1 deletions

View file

@ -0,0 +1,25 @@
# Generated by Django 2.0.9 on 2018-12-27 16:05
import django.contrib.postgres.fields.jsonb
from django.db import migrations, models
import funkwhale_api.federation.models
class Migration(migrations.Migration):
dependencies = [("federation", "0015_populate_domains")]
operations = [
migrations.AddField(
model_name="domain",
name="nodeinfo",
field=django.contrib.postgres.fields.jsonb.JSONField(
default=funkwhale_api.federation.models.empty_dict, max_length=50000
),
),
migrations.AddField(
model_name="domain",
name="nodeinfo_fetch_date",
field=models.DateTimeField(blank=True, default=None, null=True),
),
]

View file

@ -87,6 +87,9 @@ class DomainQuerySet(models.QuerySet):
class Domain(models.Model):
name = models.CharField(primary_key=True, max_length=255)
creation_date = models.DateTimeField(default=timezone.now)
nodeinfo_fetch_date = models.DateTimeField(default=None, null=True, blank=True)
nodeinfo = JSONField(default=empty_dict, max_length=50000)
objects = DomainQuerySet.as_manager()
def __str__(self):

View file

@ -889,3 +889,15 @@ class CollectionSerializer(serializers.Serializer):
if self.context.get("include_ap_context", True):
d["@context"] = AP_CONTEXT
return d
class NodeInfoLinkSerializer(serializers.Serializer):
href = serializers.URLField()
rel = serializers.URLField()
class NodeInfoSerializer(serializers.Serializer):
links = serializers.ListField(
child=NodeInfoLinkSerializer(),
min_length=1
)

View file

@ -1,6 +1,7 @@
import datetime
import logging
import os
import requests
from django.conf import settings
from django.db.models import Q, F
@ -14,6 +15,7 @@ from funkwhale_api.music import models as music_models
from funkwhale_api.taskapp import celery
from . import models, signing
from . import serializers
from . import routes
logger = logging.getLogger(__name__)
@ -147,3 +149,40 @@ def deliver_to_remote(delivery):
delivery.attempts = F("attempts") + 1
delivery.is_delivered = True
delivery.save(update_fields=["last_attempt_date", "attempts", "is_delivered"])
def fetch_nodeinfo(domain_name):
s = session.get_session()
wellknown_url = "https://{}/.well-known/nodeinfo".format(domain_name)
response = s.get(
url=wellknown_url, timeout=5, verify=settings.EXTERNAL_REQUESTS_VERIFY_SSL
)
response.raise_for_status()
serializer = serializers.NodeInfoSerializer(data=response.json())
serializer.is_valid(raise_exception=True)
nodeinfo_url = None
for link in serializer.validated_data["links"]:
if link["rel"] == "http://nodeinfo.diaspora.software/ns/schema/2.0":
nodeinfo_url = link["href"]
break
response = s.get(
url=nodeinfo_url, timeout=5, verify=settings.EXTERNAL_REQUESTS_VERIFY_SSL
)
response.raise_for_status()
return response.json()
@celery.app.task(name="federation.update_domain_nodeinfo")
@celery.require_instance(
models.Domain.objects.external(), "domain", id_kwarg_name="domain_name"
)
def update_domain_nodeinfo(domain):
now = timezone.now()
try:
nodeinfo = {"status": "ok", "payload": fetch_nodeinfo(domain.name)}
except (requests.RequestException, serializers.serializers.ValidationError) as e:
nodeinfo = {"status": "error", "error": str(e)}
domain.nodeinfo_fetch_date = now
domain.nodeinfo = nodeinfo
domain.save(update_fields=["nodeinfo", "nodeinfo_fetch_date"])

View file

@ -184,6 +184,8 @@ class ManageDomainSerializer(serializers.ModelSerializer):
"actors_count",
"last_activity_date",
"outbox_activities_count",
"nodeinfo",
"nodeinfo_fetch_date",
]
def get_actors_count(self, o):

View file

@ -1,8 +1,9 @@
from rest_framework import mixins, response, viewsets
from rest_framework.decorators import list_route
from rest_framework.decorators import detail_route, list_route
from funkwhale_api.common import preferences
from funkwhale_api.federation import models as federation_models
from funkwhale_api.federation import tasks as federation_tasks
from funkwhale_api.music import models as music_models
from funkwhale_api.users import models as users_models
from funkwhale_api.users.permissions import HasUserPermission
@ -98,6 +99,7 @@ class ManageInvitationViewSet(
class ManageDomainViewSet(
mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet
):
lookup_value_regex = "[a-zA-Z0-9\-\.]+"
queryset = (
federation_models.Domain.objects.external()
.with_last_activity_date()
@ -116,3 +118,10 @@ class ManageDomainViewSet(
"actors_count",
"outbox_activities_count",
]
@detail_route(methods=["get"])
def nodeinfo(self, request, *args, **kwargs):
domain = self.get_object()
federation_tasks.update_domain_nodeinfo(domain_name=domain.name)
domain.refresh_from_db()
return response.Response(domain.nodeinfo, status=200)