Added API to list and detail actors

merge-requests/552/head
Eliot Berriot 2019-01-03 11:47:29 +01:00
rodzic bbc36201c8
commit 47209ee5ae
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: DD6965E2476E5C27
7 zmienionych plików z 174 dodań i 2 usunięć

Wyświetl plik

@ -61,6 +61,21 @@ class ActorQuerySet(models.QuerySet):
return qs
def with_outbox_activities_count(self):
return self.annotate(
outbox_activities_count=models.Count("outbox_activities", distinct=True)
)
def with_followers_count(self):
return self.annotate(
followers_count=models.Count("received_follows", distinct=True)
)
def with_uploads_count(self):
return self.annotate(
uploads_count=models.Count("libraries__uploads", distinct=True)
)
class DomainQuerySet(models.QuerySet):
def external(self):
@ -71,7 +86,7 @@ class DomainQuerySet(models.QuerySet):
def with_outbox_activities_count(self):
return self.annotate(
outbox_activities_count=models.Count("actors__outbox_activities")
outbox_activities_count=models.Count("actors__outbox_activities", distinct=True)
)

Wyświetl plik

@ -1,6 +1,8 @@
from django_filters import rest_framework as filters
from funkwhale_api.common import fields
from funkwhale_api.common import search
from funkwhale_api.federation import models as federation_models
from funkwhale_api.music import models as music_models
from funkwhale_api.users import models as users_models
@ -29,6 +31,28 @@ class ManageDomainFilterSet(filters.FilterSet):
fields = ["name"]
class ManageActorFilterSet(filters.FilterSet):
q = fields.SmartSearchFilter(
config=search.SearchConfig(
search_fields={
"name": {"to": "name"},
"username": {"to": "preferred_username"},
"bio": {"to": "summary"},
"type": {"to": "type"},
},
filter_fields={"domain": {"to": "domain_id__iexact"}},
)
)
local = filters.BooleanFilter(name="_", method="filter_local")
class Meta:
model = federation_models.Actor
fields = ["q", "domain", "type", "manually_approves_followers", "local"]
def filter_local(self, queryset, name, value):
return queryset.local(value)
class ManageUserFilterSet(filters.FilterSet):
q = fields.SearchFilter(search_fields=["username", "email", "name"])

Wyświetl plik

@ -191,3 +191,40 @@ class ManageDomainSerializer(serializers.ModelSerializer):
def get_outbox_activities_count(self, o):
return getattr(o, "outbox_activities_count", 0)
class ManageActorSerializer(serializers.ModelSerializer):
outbox_activities_count = serializers.SerializerMethodField()
uploads_count = serializers.SerializerMethodField()
followers_count = serializers.SerializerMethodField()
class Meta:
model = federation_models.Actor
fields = [
"id",
"url",
"fid",
"preferred_username",
"domain",
"name",
"summary",
"type",
"creation_date",
"last_fetch_date",
"inbox_url",
"outbox_url",
"shared_inbox_url",
"manually_approves_followers",
"outbox_activities_count",
"uploads_count",
"followers_count",
]
def get_uploads_count(self, o):
return getattr(o, "uploads_count", 0)
def get_followers_count(self, o):
return getattr(o, "followers_count", 0)
def get_outbox_activities_count(self, o):
return getattr(o, "outbox_activities_count", 0)

Wyświetl plik

@ -11,6 +11,9 @@ users_router = routers.SimpleRouter()
users_router.register(r"users", views.ManageUserViewSet, "users")
users_router.register(r"invitations", views.ManageInvitationViewSet, "invitations")
other_router = routers.SimpleRouter()
other_router.register(r"accounts", views.ManageActorViewSet, "accounts")
urlpatterns = [
url(
r"^federation/",
@ -18,4 +21,4 @@ urlpatterns = [
),
url(r"^library/", include((library_router.urls, "instance"), namespace="library")),
url(r"^users/", include((users_router.urls, "instance"), namespace="users")),
]
] + other_router.urls

Wyświetl plik

@ -1,5 +1,6 @@
from rest_framework import mixins, response, viewsets
from rest_framework.decorators import detail_route, list_route
from django.shortcuts import get_object_or_404
from funkwhale_api.common import preferences
from funkwhale_api.federation import models as federation_models
@ -129,3 +130,45 @@ class ManageDomainViewSet(
def stats(self, request, *args, **kwargs):
domain = self.get_object()
return response.Response(domain.get_stats(), status=200)
class ManageActorViewSet(
mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet
):
lookup_value_regex = r"([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)"
queryset = (
federation_models.Actor.objects.all()
.with_outbox_activities_count()
.with_followers_count()
.with_uploads_count()
.order_by("-creation_date")
)
serializer_class = serializers.ManageActorSerializer
filter_class = filters.ManageActorFilterSet
permission_classes = (HasUserPermission,)
required_permissions = ["moderation"]
ordering_fields = [
"name",
"preferred_username",
"domain",
"fid",
"creation_date",
"last_fetch_date",
"uploads_count",
"followers_count",
"outbox_activities_count",
]
def get_object(self):
queryset = self.filter_queryset(self.get_queryset())
username, domain = self.kwargs["pk"].split("@")
filter_kwargs = {"domain_id": domain, "preferred_username": username}
obj = get_object_or_404(queryset, **filter_kwargs)
self.check_object_permissions(self.request, obj)
return obj
@detail_route(methods=["get"])
def stats(self, request, *args, **kwargs):
domain = self.get_object()
return response.Response(domain.get_stats(), status=200)

Wyświetl plik

@ -51,3 +51,32 @@ def test_manage_domain_serializer(factories, now):
s = serializers.ManageDomainSerializer(domain)
assert s.data == expected
def test_manage_actor_serializer(factories, now):
actor = factories["federation.Actor"]()
setattr(actor, "outbox_activities_count", 23)
setattr(actor, "followers_count", 42)
setattr(actor, "uploads_count", 66)
expected = {
"id": actor.id,
"name": actor.name,
"creation_date": actor.creation_date.isoformat().split("+")[0] + "Z",
"last_fetch_date": actor.last_fetch_date.isoformat().split("+")[0] + "Z",
"outbox_activities_count": 23,
"followers_count": 42,
"uploads_count": 66,
"fid": actor.fid,
"url": actor.url,
"outbox_url": actor.outbox_url,
"shared_inbox_url": actor.shared_inbox_url,
"inbox_url": actor.inbox_url,
"domain": actor.domain_id,
"type": actor.type,
"summary": actor.summary,
"preferred_username": actor.preferred_username,
"manually_approves_followers": actor.manually_approves_followers,
}
s = serializers.ManageActorSerializer(actor)
assert s.data == expected

Wyświetl plik

@ -12,6 +12,7 @@ from funkwhale_api.manage import serializers, views
(views.ManageUserViewSet, ["settings"], "and"),
(views.ManageInvitationViewSet, ["settings"], "and"),
(views.ManageDomainViewSet, ["moderation"], "and"),
(views.ManageActorViewSet, ["moderation"], "and"),
],
)
def test_permissions(assert_user_permission, view, permissions, operator):
@ -112,3 +113,23 @@ def test_domain_stats(factories, superuser_api_client, mocker):
response = superuser_api_client.get(url)
assert response.status_code == 200
assert response.data == {"hello": "world"}
def test_actor_list(factories, superuser_api_client, settings):
actor = factories["federation.Actor"]()
url = reverse("api:v1:manage:accounts-list")
response = superuser_api_client.get(url)
assert response.status_code == 200
assert response.data["count"] == 1
assert response.data["results"][0]["id"] == actor.id
def test_actor_detail(factories, superuser_api_client):
actor = factories["federation.Actor"]()
url = reverse("api:v1:manage:accounts-detail", kwargs={"pk": actor.full_username})
response = superuser_api_client.get(url)
assert response.status_code == 200
assert response.data["id"] == actor.id