Newer
Older
import json
import urllib.parse
from django.conf import settings
from django.core.serializers.json import DjangoJSONEncoder
import persisting_theory
from rest_framework import serializers
from funkwhale_api.common import fields as common_fields
from funkwhale_api.common import preferences
from funkwhale_api.federation import models as federation_models
from funkwhale_api.federation import utils as federation_utils
from funkwhale_api.music import models as music_models
from funkwhale_api.playlists import models as playlists_models
from . import tasks
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class FilteredArtistSerializer(serializers.ModelSerializer):
class Meta:
model = music_models.Artist
fields = ["id", "name"]
class TargetSerializer(serializers.Serializer):
type = serializers.ChoiceField(choices=["artist"])
id = serializers.CharField()
def to_representation(self, value):
if value["type"] == "artist":
data = FilteredArtistSerializer(value["obj"]).data
data.update({"type": "artist"})
return data
def to_internal_value(self, value):
if value["type"] == "artist":
field = serializers.PrimaryKeyRelatedField(
queryset=music_models.Artist.objects.all()
)
value["obj"] = field.to_internal_value(value["id"])
return value
class UserFilterSerializer(serializers.ModelSerializer):
target = TargetSerializer()
class Meta:
model = models.UserFilter
fields = ["uuid", "target", "creation_date"]
read_only_fields = ["uuid", "creation_date"]
def validate(self, data):
target = data.pop("target")
if target["type"] == "artist":
data["target_artist"] = target["obj"]
return data
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
state_serializers = persisting_theory.Registry()
TAGS_FIELD = serializers.ListField(source="get_tags")
@state_serializers.register(name="music.Artist")
class ArtistStateSerializer(serializers.ModelSerializer):
tags = TAGS_FIELD
class Meta:
model = music_models.Artist
fields = ["id", "name", "mbid", "fid", "creation_date", "uuid", "tags"]
@state_serializers.register(name="music.Album")
class AlbumStateSerializer(serializers.ModelSerializer):
tags = TAGS_FIELD
artist = ArtistStateSerializer()
class Meta:
model = music_models.Album
fields = [
"id",
"title",
"mbid",
"fid",
"creation_date",
"uuid",
"artist",
"release_date",
"tags",
]
@state_serializers.register(name="music.Track")
class TrackStateSerializer(serializers.ModelSerializer):
tags = TAGS_FIELD
artist = ArtistStateSerializer()
album = AlbumStateSerializer()
class Meta:
model = music_models.Track
fields = [
"id",
"title",
"mbid",
"fid",
"creation_date",
"uuid",
"artist",
"album",
"disc_number",
"position",
"license",
"copyright",
"tags",
]
@state_serializers.register(name="music.Library")
class LibraryStateSerializer(serializers.ModelSerializer):
class Meta:
model = music_models.Library
fields = [
"id",
"uuid",
"fid",
"name",
"description",
"creation_date",
"privacy_level",
]
@state_serializers.register(name="playlists.Playlist")
class PlaylistStateSerializer(serializers.ModelSerializer):
class Meta:
model = playlists_models.Playlist
fields = ["id", "name", "creation_date", "privacy_level"]
@state_serializers.register(name="federation.Actor")
class ActorStateSerializer(serializers.ModelSerializer):
class Meta:
model = federation_models.Actor
fields = [
"fid",
"name",
"preferred_username",
"full_username",
"summary",
"domain",
"type",
"creation_date",
]
def get_actor_query(attr, value):
data = federation_utils.get_actor_data_from_username(value)
return federation_utils.get_actor_from_username_data_query(None, data)
def get_target_owner(target):
mapping = {
music_models.Artist: lambda t: t.attributed_to,
music_models.Album: lambda t: t.attributed_to,
music_models.Track: lambda t: t.attributed_to,
music_models.Library: lambda t: t.actor,
playlists_models.Playlist: lambda t: t.user.actor,
federation_models.Actor: lambda t: t,
}
return mapping[target.__class__](target)
TARGET_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",
"id_field": serializers.UUIDField(),
},
"playlist": {"queryset": playlists_models.Playlist.objects.all()},
"account": {
"queryset": federation_models.Actor.objects.all(),
"id_attr": "full_username",
"id_field": serializers.EmailField(),
"get_query": get_actor_query,
},
}
TARGET_FIELD = common_fields.GenericRelation(TARGET_CONFIG)
def get_target_state(target):
state = {}
target_state_serializer = state_serializers[target._meta.label]
state = target_state_serializer(target).data
# freeze target type/id in JSON so even if the corresponding object is deleted
# we can have the info and display it in the frontend
target_data = TARGET_FIELD.to_representation(target)
state["_target"] = json.loads(json.dumps(target_data, cls=DjangoJSONEncoder))
if "fid" in state:
state["domain"] = urllib.parse.urlparse(state["fid"]).hostname
state["is_local"] = (
state.get("domain", settings.FEDERATION_HOSTNAME)
== settings.FEDERATION_HOSTNAME
)
return state
class ReportSerializer(serializers.ModelSerializer):
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
class Meta:
model = models.Report
fields = [
"uuid",
"summary",
"creation_date",
"handled_date",
"is_handled",
"submitter_email",
"target",
"type",
]
read_only_fields = ["uuid", "is_handled", "creation_date", "handled_date"]
def validate(self, validated_data):
validated_data = super().validate(validated_data)
submitter = self.context.get("submitter")
if submitter:
# we have an authenticated actor so no need to check further
return validated_data
unauthenticated_report_types = preferences.get(
"moderation__unauthenticated_report_types"
)
if validated_data["type"] not in unauthenticated_report_types:
raise serializers.ValidationError(
"You need an account to submit this report"
)
if not validated_data.get("submitter_email"):
raise serializers.ValidationError(
"You need to provide an email address to submit this report"
)
return validated_data
def create(self, validated_data):
validated_data["target_state"] = get_target_state(validated_data["target"])
validated_data["target_owner"] = get_target_owner(validated_data["target"])
r = super().create(validated_data)
tasks.signals.report_created.send(sender=None, report=r)
return r