See #170: fetching remote objects

This commit is contained in:
Eliot Berriot 2020-03-02 17:23:03 +01:00
parent 65097f6297
commit c2eeee5eb1
30 changed files with 1173 additions and 169 deletions

View file

@ -1,7 +1,13 @@
import datetime
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.core import validators
from django.utils import timezone
from rest_framework import serializers
from funkwhale_api.common import fields as common_fields
from funkwhale_api.common import serializers as common_serializers
from funkwhale_api.music import models as music_models
from funkwhale_api.users import serializers as users_serializers
@ -158,8 +164,21 @@ class InboxItemActionSerializer(common_serializers.ActionSerializer):
return objects.update(is_read=True)
FETCH_OBJECT_CONFIG = {
"artist": {"queryset": music_models.Artist.objects.all()},
"album": {"queryset": music_models.Album.objects.all()},
"track": {"queryset": music_models.Track.objects.all()},
"library": {"queryset": music_models.Library.objects.all(), "id_attr": "uuid"},
"upload": {"queryset": music_models.Upload.objects.all(), "id_attr": "uuid"},
"account": {"queryset": models.Actor.objects.all(), "id_attr": "full_username"},
}
FETCH_OBJECT_FIELD = common_fields.GenericRelation(FETCH_OBJECT_CONFIG)
class FetchSerializer(serializers.ModelSerializer):
actor = federation_serializers.APIActorSerializer()
actor = federation_serializers.APIActorSerializer(read_only=True)
object = serializers.CharField(write_only=True)
force = serializers.BooleanField(default=False, required=False, write_only=True)
class Meta:
model = models.Fetch
@ -171,7 +190,63 @@ class FetchSerializer(serializers.ModelSerializer):
"detail",
"creation_date",
"fetch_date",
"object",
"force",
]
read_only_fields = [
"id",
"url",
"actor",
"status",
"detail",
"creation_date",
"fetch_date",
]
def validate_object(self, value):
# if value is a webginfer lookup, we craft a special url
if value.startswith("@"):
value = value.lstrip("@")
validator = validators.EmailValidator()
try:
validator(value)
except validators.ValidationError:
return value
return "webfinger://{}".format(value)
def create(self, validated_data):
check_duplicates = not validated_data.get("force", False)
if check_duplicates:
# first we check for duplicates
duplicate = (
validated_data["actor"]
.fetches.filter(
status="finished",
url=validated_data["object"],
creation_date__gte=timezone.now()
- datetime.timedelta(
seconds=settings.FEDERATION_DUPLICATE_FETCH_DELAY
),
)
.order_by("-creation_date")
.first()
)
if duplicate:
return duplicate
fetch = models.Fetch.objects.create(
actor=validated_data["actor"], url=validated_data["object"]
)
return fetch
def to_representation(self, obj):
repr = super().to_representation(obj)
object_data = None
if obj.object:
object_data = FETCH_OBJECT_FIELD.to_representation(obj.object)
repr["object"] = object_data
return repr
class FullActorSerializer(serializers.Serializer):