kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
Added API to list and detail actors
rodzic
bbc36201c8
commit
47209ee5ae
|
@ -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)
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -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"])
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Ładowanie…
Reference in New Issue