From 002b3687a81571ad3f23001c1ab036f1969d54e4 Mon Sep 17 00:00:00 2001
From: Eliot Berriot <contact@eliotberriot.com>
Date: Thu, 26 Dec 2019 11:28:12 +0100
Subject: [PATCH] Advertise list of known nodes on /api/v1/federation/domains
and in nodeinfo if stats sharing is enabled
---
.../federation/api_serializers.py | 4 ++++
api/funkwhale_api/federation/api_urls.py | 1 +
api/funkwhale_api/federation/api_views.py | 21 +++++++++++++++++++
api/funkwhale_api/instance/nodeinfo.py | 8 +++++++
api/tests/federation/test_api_views.py | 18 ++++++++++++++++
api/tests/instance/test_nodeinfo.py | 7 +++++++
changes/changelog.d/known-nodes.enhancement | 1 +
7 files changed, 60 insertions(+)
create mode 100644 changes/changelog.d/known-nodes.enhancement
diff --git a/api/funkwhale_api/federation/api_serializers.py b/api/funkwhale_api/federation/api_serializers.py
index 93dae4e5..2a1143ec 100644
--- a/api/funkwhale_api/federation/api_serializers.py
+++ b/api/funkwhale_api/federation/api_serializers.py
@@ -27,6 +27,10 @@ class LibraryScanSerializer(serializers.ModelSerializer):
]
+class DomainSerializer(serializers.Serializer):
+ name = serializers.CharField()
+
+
class LibrarySerializer(serializers.ModelSerializer):
actor = federation_serializers.APIActorSerializer()
uploads_count = serializers.SerializerMethodField()
diff --git a/api/funkwhale_api/federation/api_urls.py b/api/funkwhale_api/federation/api_urls.py
index 896fa243..4f0471b1 100644
--- a/api/funkwhale_api/federation/api_urls.py
+++ b/api/funkwhale_api/federation/api_urls.py
@@ -7,5 +7,6 @@ router.register(r"fetches", api_views.FetchViewSet, "fetches")
router.register(r"follows/library", api_views.LibraryFollowViewSet, "library-follows")
router.register(r"inbox", api_views.InboxItemViewSet, "inbox")
router.register(r"libraries", api_views.LibraryViewSet, "libraries")
+router.register(r"domains", api_views.DomainViewSet, "domains")
urlpatterns = router.urls
diff --git a/api/funkwhale_api/federation/api_views.py b/api/funkwhale_api/federation/api_views.py
index 5f6f50d8..395290be 100644
--- a/api/funkwhale_api/federation/api_views.py
+++ b/api/funkwhale_api/federation/api_views.py
@@ -9,6 +9,8 @@ from rest_framework import permissions
from rest_framework import response
from rest_framework import viewsets
+from funkwhale_api.common import preferences
+from funkwhale_api.common.permissions import ConditionalAuthentication
from funkwhale_api.music import models as music_models
from funkwhale_api.users.oauth import permissions as oauth_permissions
@@ -197,3 +199,22 @@ class FetchViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
queryset = models.Fetch.objects.select_related("actor")
serializer_class = api_serializers.FetchSerializer
permission_classes = [permissions.IsAuthenticated]
+
+
+class DomainViewSet(
+ mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet
+):
+ queryset = models.Domain.objects.order_by("name").external()
+ permission_classes = [ConditionalAuthentication]
+ serializer_class = api_serializers.DomainSerializer
+ ordering_fields = ("creation_date", "name")
+ max_page_size = 100
+
+ def get_queryset(self):
+ qs = super().get_queryset()
+ qs = qs.exclude(
+ instance_policy__is_active=True, instance_policy__block_all=True
+ )
+ if preferences.get("moderation__allow_list_enabled"):
+ qs = qs.filter(allowed=True)
+ return qs
diff --git a/api/funkwhale_api/instance/nodeinfo.py b/api/funkwhale_api/instance/nodeinfo.py
index 712578c3..9da128de 100644
--- a/api/funkwhale_api/instance/nodeinfo.py
+++ b/api/funkwhale_api/instance/nodeinfo.py
@@ -1,5 +1,7 @@
import memoize.djangocache
+from django.urls import reverse
+
import funkwhale_api
from funkwhale_api.common import preferences
from funkwhale_api.federation import actors, models as federation_models
@@ -18,6 +20,7 @@ def get():
share_stats = all_preferences.get("instance__nodeinfo_stats_enabled")
allow_list_enabled = all_preferences.get("moderation__allow_list_enabled")
allow_list_public = all_preferences.get("moderation__allow_list_public")
+ auth_required = all_preferences.get("common__api_authentication_required")
banner = all_preferences.get("instance__banner")
unauthenticated_report_types = all_preferences.get(
"moderation__unauthenticated_report_types"
@@ -67,6 +70,7 @@ def get():
"instance__funkwhale_support_message_enabled"
),
"instanceSupportMessage": all_preferences.get("instance__support_message"),
+ "knownNodesListUrl": None,
},
}
@@ -87,4 +91,8 @@ def get():
"favorites": {"tracks": {"total": statistics["track_favorites"]}},
"listenings": {"total": statistics["listenings"]},
}
+ if not auth_required:
+ data["metadata"]["knownNodesListUrl"] = federation_utils.full_url(
+ reverse("api:v1:federation:domains-list")
+ )
return data
diff --git a/api/tests/federation/test_api_views.py b/api/tests/federation/test_api_views.py
index c34c5e99..1795a65e 100644
--- a/api/tests/federation/test_api_views.py
+++ b/api/tests/federation/test_api_views.py
@@ -179,3 +179,21 @@ def test_can_detail_fetch(logged_in_api_client, factories):
assert response.status_code == 200
assert response.data == expected
+
+
+def test_user_can_list_domains(factories, api_client, preferences):
+ preferences["common__api_authentication_required"] = False
+ allowed = factories["federation.Domain"]()
+ factories["moderation.InstancePolicy"](
+ actor=None, for_domain=True, block_all=True
+ ).target_domain
+ url = reverse("api:v1:federation:domains-list")
+ response = api_client.get(url)
+
+ expected = {
+ "count": 1,
+ "next": None,
+ "previous": None,
+ "results": [api_serializers.DomainSerializer(allowed).data],
+ }
+ assert response.data == expected
diff --git a/api/tests/instance/test_nodeinfo.py b/api/tests/instance/test_nodeinfo.py
index 2e9075d2..bdca8f45 100644
--- a/api/tests/instance/test_nodeinfo.py
+++ b/api/tests/instance/test_nodeinfo.py
@@ -1,5 +1,7 @@
import pytest
+from django.urls import reverse
+
import funkwhale_api
from funkwhale_api.instance import nodeinfo
from funkwhale_api.federation import actors
@@ -10,6 +12,7 @@ from funkwhale_api.music import utils as music_utils
def test_nodeinfo_dump(preferences, mocker, avatar):
preferences["instance__banner"] = avatar
preferences["instance__nodeinfo_stats_enabled"] = True
+ preferences["common__api_authentication_required"] = False
preferences["moderation__unauthenticated_report_types"] = [
"takedown_request",
"other",
@@ -91,6 +94,9 @@ def test_nodeinfo_dump(preferences, mocker, avatar):
"instance__funkwhale_support_message_enabled"
],
"instanceSupportMessage": preferences["instance__support_message"],
+ "knownNodesListUrl": federation_utils.full_url(
+ reverse("api:v1:federation:domains-list")
+ ),
},
}
assert nodeinfo.get() == expected
@@ -159,6 +165,7 @@ def test_nodeinfo_dump_stats_disabled(preferences, mocker):
"instance__funkwhale_support_message_enabled"
],
"instanceSupportMessage": preferences["instance__support_message"],
+ "knownNodesListUrl": None,
},
}
assert nodeinfo.get() == expected
diff --git a/changes/changelog.d/known-nodes.enhancement b/changes/changelog.d/known-nodes.enhancement
new file mode 100644
index 00000000..00497de4
--- /dev/null
+++ b/changes/changelog.d/known-nodes.enhancement
@@ -0,0 +1 @@
+Advertise list of known nodes on /api/v1/federation/domains and in nodeinfo if stats sharing is enabled
--
GitLab