From e82a53da3570128d493d85c13762dd8493f7a975 Mon Sep 17 00:00:00 2001
From: Eliot Berriot <contact@eliotberriot.com>
Date: Tue, 10 Apr 2018 23:17:51 +0200
Subject: [PATCH] Added API endpoints to list library followees and followers

---
 api/funkwhale_api/federation/filters.py     | 19 +++++++++++
 api/funkwhale_api/federation/serializers.py | 19 +++++++++++
 api/funkwhale_api/federation/views.py       | 35 +++++++++++++++++++++
 api/tests/federation/test_views.py          | 28 +++++++++++++++++
 4 files changed, 101 insertions(+)
 create mode 100644 api/funkwhale_api/federation/filters.py

diff --git a/api/funkwhale_api/federation/filters.py b/api/funkwhale_api/federation/filters.py
new file mode 100644
index 0000000000..a43c2dc0c7
--- /dev/null
+++ b/api/funkwhale_api/federation/filters.py
@@ -0,0 +1,19 @@
+import django_filters
+
+from . import models
+
+
+class FollowFilter(django_filters.FilterSet):
+    ordering = django_filters.OrderingFilter(
+        # tuple-mapping retains order
+        fields=(
+            ('creation_date', 'creation_date'),
+            ('modification_date', 'modification_date'),
+        ),
+    )
+
+    class Meta:
+        model = models.Follow
+        fields = {
+            'approved': ['exact'],
+        }
diff --git a/api/funkwhale_api/federation/serializers.py b/api/funkwhale_api/federation/serializers.py
index 68eef13550..0fe52e1f5f 100644
--- a/api/funkwhale_api/federation/serializers.py
+++ b/api/funkwhale_api/federation/serializers.py
@@ -96,6 +96,22 @@ class ActorSerializer(serializers.ModelSerializer):
             return value[:500]
 
 
+class APIActorSerializer(serializers.ModelSerializer):
+    class Meta:
+        model = models.Actor
+        fields = [
+            'id',
+            'url',
+            'creation_date',
+            'summary',
+            'preferred_username',
+            'name',
+            'last_fetch_date',
+            'domain',
+            'type',
+            'manually_approves_followers',
+
+        ]
 class LibraryActorSerializer(ActorSerializer):
     url = serializers.ListField(
         child=serializers.JSONField())
@@ -224,6 +240,9 @@ class FollowSerializer(serializers.Serializer):
 
 
 class APIFollowSerializer(serializers.ModelSerializer):
+    actor = APIActorSerializer()
+    target = APIActorSerializer()
+
     class Meta:
         model = models.Follow
         fields = [
diff --git a/api/funkwhale_api/federation/views.py b/api/funkwhale_api/federation/views.py
index 623fd574f1..5b11942f23 100644
--- a/api/funkwhale_api/federation/views.py
+++ b/api/funkwhale_api/federation/views.py
@@ -18,6 +18,7 @@ from funkwhale_api.music.models import TrackFile
 from . import activity
 from . import actors
 from . import authentication
+from . import filters
 from . import library
 from . import models
 from . import permissions
@@ -177,6 +178,40 @@ class LibraryViewSet(viewsets.GenericViewSet):
         data = library.scan_from_account_name(account)
         return response.Response(data)
 
+    @list_route(methods=['get'])
+    def following(self, request, *args, **kwargs):
+        library_actor = actors.SYSTEM_ACTORS['library'].get_actor_instance()
+        queryset = models.Follow.objects.filter(
+            actor=library_actor
+        ).select_related(
+            'target',
+            'target',
+        ).order_by('-creation_date')
+        filterset = filters.FollowFilter(request.GET, queryset=queryset)
+        serializer = serializers.APIFollowSerializer(filterset.qs, many=True)
+        data = {
+            'results': serializer.data,
+            'count': len(filterset.qs),
+        }
+        return response.Response(data)
+
+    @list_route(methods=['get'])
+    def followers(self, request, *args, **kwargs):
+        library_actor = actors.SYSTEM_ACTORS['library'].get_actor_instance()
+        queryset = models.Follow.objects.filter(
+            target=library_actor
+        ).select_related(
+            'target',
+            'target',
+        ).order_by('-creation_date')
+        filterset = filters.FollowFilter(request.GET, queryset=queryset)
+        serializer = serializers.APIFollowSerializer(filterset.qs, many=True)
+        data = {
+            'results': serializer.data,
+            'count': len(filterset.qs),
+        }
+        return response.Response(data)
+
     @transaction.atomic
     def create(self, request, *args, **kwargs):
         serializer = serializers.APILibraryCreateSerializer(data=request.data)
diff --git a/api/tests/federation/test_views.py b/api/tests/federation/test_views.py
index 99d4256619..3bc9fa88f2 100644
--- a/api/tests/federation/test_views.py
+++ b/api/tests/federation/test_views.py
@@ -233,3 +233,31 @@ def test_follow_library(superuser_api_client, mocker, factories, r_mock):
         on_behalf_of=library_actor,
         to=[actor.url]
     )
+
+
+def test_can_list_system_actor_following(factories, superuser_api_client):
+    library_actor = actors.SYSTEM_ACTORS['library'].get_actor_instance()
+    follow1 = factories['federation.Follow'](actor=library_actor)
+    follow2 = factories['federation.Follow']()
+
+    url = reverse('api:v1:federation:libraries-following')
+    response = superuser_api_client.get(url)
+
+    assert response.status_code == 200
+    assert response.data['results'] == [
+        serializers.APIFollowSerializer(follow1).data
+    ]
+
+
+def test_can_list_system_actor_followers(factories, superuser_api_client):
+    library_actor = actors.SYSTEM_ACTORS['library'].get_actor_instance()
+    follow1 = factories['federation.Follow'](actor=library_actor)
+    follow2 = factories['federation.Follow'](target=library_actor)
+
+    url = reverse('api:v1:federation:libraries-followers')
+    response = superuser_api_client.get(url)
+
+    assert response.status_code == 200
+    assert response.data['results'] == [
+        serializers.APIFollowSerializer(follow2).data
+    ]
-- 
GitLab