2018-09-06 18:35:02 +00:00
|
|
|
import requests.exceptions
|
|
|
|
|
2018-09-13 15:18:23 +00:00
|
|
|
from django.db import transaction
|
2018-09-06 18:35:02 +00:00
|
|
|
from django.db.models import Count
|
|
|
|
|
|
|
|
from rest_framework import decorators
|
|
|
|
from rest_framework import mixins
|
2019-04-18 12:37:17 +00:00
|
|
|
from rest_framework import permissions
|
2018-09-06 18:35:02 +00:00
|
|
|
from rest_framework import response
|
|
|
|
from rest_framework import viewsets
|
|
|
|
|
|
|
|
from funkwhale_api.music import models as music_models
|
2019-03-25 16:02:51 +00:00
|
|
|
from funkwhale_api.users.oauth import permissions as oauth_permissions
|
2018-09-06 18:35:02 +00:00
|
|
|
|
2018-09-13 15:18:23 +00:00
|
|
|
from . import activity
|
2018-09-06 18:35:02 +00:00
|
|
|
from . import api_serializers
|
2019-01-09 16:52:14 +00:00
|
|
|
from . import exceptions
|
2018-09-06 18:35:02 +00:00
|
|
|
from . import filters
|
|
|
|
from . import models
|
|
|
|
from . import routes
|
|
|
|
from . import serializers
|
|
|
|
from . import utils
|
|
|
|
|
|
|
|
|
2018-09-13 15:18:23 +00:00
|
|
|
@transaction.atomic
|
|
|
|
def update_follow(follow, approved):
|
|
|
|
follow.approved = approved
|
|
|
|
follow.save(update_fields=["approved"])
|
2019-03-07 11:09:45 +00:00
|
|
|
if approved:
|
|
|
|
routes.outbox.dispatch({"type": "Accept"}, context={"follow": follow})
|
2018-09-13 15:18:23 +00:00
|
|
|
|
|
|
|
|
2018-09-06 18:35:02 +00:00
|
|
|
class LibraryFollowViewSet(
|
|
|
|
mixins.CreateModelMixin,
|
|
|
|
mixins.ListModelMixin,
|
|
|
|
mixins.RetrieveModelMixin,
|
2018-09-24 18:44:22 +00:00
|
|
|
mixins.DestroyModelMixin,
|
2018-09-06 18:35:02 +00:00
|
|
|
viewsets.GenericViewSet,
|
|
|
|
):
|
|
|
|
lookup_field = "uuid"
|
|
|
|
queryset = (
|
|
|
|
models.LibraryFollow.objects.all()
|
|
|
|
.order_by("-creation_date")
|
2018-09-24 18:44:22 +00:00
|
|
|
.select_related("actor", "target__actor")
|
2018-09-06 18:35:02 +00:00
|
|
|
)
|
|
|
|
serializer_class = api_serializers.LibraryFollowSerializer
|
2019-03-25 16:02:51 +00:00
|
|
|
permission_classes = [oauth_permissions.ScopePermission]
|
|
|
|
required_scope = "follows"
|
2019-01-11 11:03:06 +00:00
|
|
|
filterset_class = filters.LibraryFollowFilter
|
2018-09-06 18:35:02 +00:00
|
|
|
ordering_fields = ("creation_date",)
|
|
|
|
|
|
|
|
def get_queryset(self):
|
|
|
|
qs = super().get_queryset()
|
|
|
|
return qs.filter(actor=self.request.user.actor)
|
|
|
|
|
|
|
|
def perform_create(self, serializer):
|
|
|
|
follow = serializer.save(actor=self.request.user.actor)
|
|
|
|
routes.outbox.dispatch({"type": "Follow"}, context={"follow": follow})
|
|
|
|
|
2018-09-24 18:44:22 +00:00
|
|
|
@transaction.atomic
|
|
|
|
def perform_destroy(self, instance):
|
|
|
|
routes.outbox.dispatch(
|
|
|
|
{"type": "Undo", "object": {"type": "Follow"}}, context={"follow": instance}
|
|
|
|
)
|
|
|
|
instance.delete()
|
|
|
|
|
2018-09-06 18:35:02 +00:00
|
|
|
def get_serializer_context(self):
|
|
|
|
context = super().get_serializer_context()
|
|
|
|
context["actor"] = self.request.user.actor
|
|
|
|
return context
|
|
|
|
|
2019-01-11 12:33:35 +00:00
|
|
|
@decorators.action(methods=["post"], detail=True)
|
2018-09-13 15:18:23 +00:00
|
|
|
def accept(self, request, *args, **kwargs):
|
|
|
|
try:
|
|
|
|
follow = self.queryset.get(
|
|
|
|
target__actor=self.request.user.actor, uuid=kwargs["uuid"]
|
|
|
|
)
|
|
|
|
except models.LibraryFollow.DoesNotExist:
|
|
|
|
return response.Response({}, status=404)
|
|
|
|
update_follow(follow, approved=True)
|
|
|
|
return response.Response(status=204)
|
|
|
|
|
2019-01-11 12:33:35 +00:00
|
|
|
@decorators.action(methods=["post"], detail=True)
|
2018-09-13 15:18:23 +00:00
|
|
|
def reject(self, request, *args, **kwargs):
|
|
|
|
try:
|
|
|
|
follow = self.queryset.get(
|
|
|
|
target__actor=self.request.user.actor, uuid=kwargs["uuid"]
|
|
|
|
)
|
|
|
|
except models.LibraryFollow.DoesNotExist:
|
|
|
|
return response.Response({}, status=404)
|
|
|
|
|
|
|
|
update_follow(follow, approved=False)
|
|
|
|
return response.Response(status=204)
|
|
|
|
|
2018-09-06 18:35:02 +00:00
|
|
|
|
|
|
|
class LibraryViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
|
|
|
|
lookup_field = "uuid"
|
|
|
|
queryset = (
|
|
|
|
music_models.Library.objects.all()
|
|
|
|
.order_by("-creation_date")
|
2018-09-28 20:19:43 +00:00
|
|
|
.select_related("actor__user")
|
2018-09-22 12:29:30 +00:00
|
|
|
.annotate(_uploads_count=Count("uploads"))
|
2018-09-06 18:35:02 +00:00
|
|
|
)
|
|
|
|
serializer_class = api_serializers.LibrarySerializer
|
2019-03-25 16:02:51 +00:00
|
|
|
permission_classes = [oauth_permissions.ScopePermission]
|
|
|
|
required_scope = "libraries"
|
2018-09-06 18:35:02 +00:00
|
|
|
|
|
|
|
def get_queryset(self):
|
|
|
|
qs = super().get_queryset()
|
|
|
|
return qs.viewable_by(actor=self.request.user.actor)
|
|
|
|
|
2019-01-11 12:33:35 +00:00
|
|
|
@decorators.action(methods=["post"], detail=True)
|
2018-09-06 18:35:02 +00:00
|
|
|
def scan(self, request, *args, **kwargs):
|
2018-09-24 18:44:22 +00:00
|
|
|
library = self.get_object()
|
2018-09-28 20:19:43 +00:00
|
|
|
if library.actor.get_user():
|
2018-09-24 18:44:22 +00:00
|
|
|
return response.Response({"status": "skipped"}, 200)
|
|
|
|
|
|
|
|
scan = library.schedule_scan(actor=request.user.actor)
|
|
|
|
if scan:
|
|
|
|
return response.Response(
|
|
|
|
{
|
|
|
|
"status": "scheduled",
|
|
|
|
"scan": api_serializers.LibraryScanSerializer(scan).data,
|
|
|
|
},
|
|
|
|
200,
|
|
|
|
)
|
|
|
|
return response.Response({"status": "skipped"}, 200)
|
|
|
|
|
2019-01-11 12:33:35 +00:00
|
|
|
@decorators.action(methods=["post"], detail=False)
|
2018-09-24 18:44:22 +00:00
|
|
|
def fetch(self, request, *args, **kwargs):
|
2018-09-06 18:35:02 +00:00
|
|
|
try:
|
|
|
|
fid = request.data["fid"]
|
|
|
|
except KeyError:
|
|
|
|
return response.Response({"fid": ["This field is required"]})
|
|
|
|
try:
|
2019-01-09 16:52:14 +00:00
|
|
|
library = utils.retrieve_ap_object(
|
2018-09-06 18:35:02 +00:00
|
|
|
fid,
|
2019-03-15 11:08:45 +00:00
|
|
|
actor=request.user.actor,
|
2018-09-06 18:35:02 +00:00
|
|
|
queryset=self.queryset,
|
|
|
|
serializer_class=serializers.LibrarySerializer,
|
|
|
|
)
|
2019-01-09 16:52:14 +00:00
|
|
|
except exceptions.BlockedActorOrDomain:
|
|
|
|
return response.Response(
|
|
|
|
{"detail": "This domain/account is blocked on your instance."},
|
|
|
|
status=400,
|
|
|
|
)
|
2018-09-06 18:35:02 +00:00
|
|
|
except requests.exceptions.RequestException as e:
|
|
|
|
return response.Response(
|
2018-09-24 18:44:22 +00:00
|
|
|
{"detail": "Error while fetching the library: {}".format(str(e))},
|
2018-09-06 18:35:02 +00:00
|
|
|
status=400,
|
|
|
|
)
|
|
|
|
except serializers.serializers.ValidationError as e:
|
|
|
|
return response.Response(
|
|
|
|
{"detail": "Invalid data in remote library: {}".format(str(e))},
|
|
|
|
status=400,
|
|
|
|
)
|
|
|
|
serializer = self.serializer_class(library)
|
|
|
|
return response.Response({"count": 1, "results": [serializer.data]})
|
2018-09-13 15:18:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
class InboxItemViewSet(
|
|
|
|
mixins.UpdateModelMixin,
|
|
|
|
mixins.ListModelMixin,
|
|
|
|
mixins.RetrieveModelMixin,
|
|
|
|
viewsets.GenericViewSet,
|
|
|
|
):
|
|
|
|
|
|
|
|
queryset = (
|
|
|
|
models.InboxItem.objects.select_related("activity__actor")
|
|
|
|
.prefetch_related("activity__object", "activity__target")
|
|
|
|
.filter(activity__type__in=activity.BROADCAST_TO_USER_ACTIVITIES, type="to")
|
|
|
|
.order_by("-activity__creation_date")
|
|
|
|
)
|
|
|
|
serializer_class = api_serializers.InboxItemSerializer
|
2019-03-25 16:02:51 +00:00
|
|
|
permission_classes = [oauth_permissions.ScopePermission]
|
|
|
|
required_scope = "notifications"
|
2019-01-11 11:03:06 +00:00
|
|
|
filterset_class = filters.InboxItemFilter
|
2018-09-13 15:18:23 +00:00
|
|
|
ordering_fields = ("activity__creation_date",)
|
|
|
|
|
|
|
|
def get_queryset(self):
|
|
|
|
qs = super().get_queryset()
|
|
|
|
return qs.filter(actor=self.request.user.actor)
|
|
|
|
|
2019-01-11 12:33:35 +00:00
|
|
|
@decorators.action(methods=["post"], detail=False)
|
2018-09-13 15:18:23 +00:00
|
|
|
def action(self, request, *args, **kwargs):
|
|
|
|
queryset = self.get_queryset()
|
|
|
|
serializer = api_serializers.InboxItemActionSerializer(
|
|
|
|
request.data, queryset=queryset
|
|
|
|
)
|
|
|
|
serializer.is_valid(raise_exception=True)
|
|
|
|
result = serializer.save()
|
|
|
|
return response.Response(result, status=200)
|
2019-04-18 12:37:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
class FetchViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
|
|
|
|
|
|
|
|
queryset = models.Fetch.objects.select_related("actor")
|
|
|
|
serializer_class = api_serializers.FetchSerializer
|
|
|
|
permission_classes = [permissions.IsAuthenticated]
|