diff --git a/api/funkwhale_api/common/filters.py b/api/funkwhale_api/common/filters.py index 2d0f2b8b1..feca948bb 100644 --- a/api/funkwhale_api/common/filters.py +++ b/api/funkwhale_api/common/filters.py @@ -91,7 +91,11 @@ def get_boolean_filter(name): def get_generic_relation_filter(relation_name, choices): - return {"handler": lambda v: fields.get_generic_filter_query(v, relation_name=relation_name, choices=choices)} + return { + "handler": lambda v: fields.get_generic_filter_query( + v, relation_name=relation_name, choices=choices + ) + } class DummyTypedMultipleChoiceField(forms.TypedMultipleChoiceField): diff --git a/api/funkwhale_api/manage/filters.py b/api/funkwhale_api/manage/filters.py index 263af9635..de9758d28 100644 --- a/api/funkwhale_api/manage/filters.py +++ b/api/funkwhale_api/manage/filters.py @@ -358,7 +358,9 @@ class ManageReportFilterSet(filters.FilterSet): "assigned_to": get_actor_filter("assigned_to"), "target_owner": get_actor_filter("target_owner"), "submitter_email": {"to": "submitter_email"}, - "target": common_filters.get_generic_relation_filter("target", moderation_serializers.TARGET_CONFIG), + "target": common_filters.get_generic_relation_filter( + "target", moderation_serializers.TARGET_CONFIG + ), }, ) ) @@ -375,7 +377,9 @@ class ManageNoteFilterSet(filters.FilterSet): filter_fields={ "uuid": {"to": "uuid"}, "author": get_actor_filter("author"), - "target": common_filters.get_generic_relation_filter("target", moderation_utils.NOTE_TARGET_FIELDS), + "target": common_filters.get_generic_relation_filter( + "target", moderation_utils.NOTE_TARGET_FIELDS + ), }, ) ) diff --git a/api/funkwhale_api/manage/serializers.py b/api/funkwhale_api/manage/serializers.py index 134cfefcd..21612ab78 100644 --- a/api/funkwhale_api/manage/serializers.py +++ b/api/funkwhale_api/manage/serializers.py @@ -651,12 +651,10 @@ class ManageBaseNoteSerializer(serializers.ModelSerializer): class ManageNoteSerializer(ManageBaseNoteSerializer): - target = common_fields.GenericRelation( - moderation_utils.NOTE_TARGET_FIELDS - ) + target = common_fields.GenericRelation(moderation_utils.NOTE_TARGET_FIELDS) class Meta(ManageBaseNoteSerializer.Meta): - fields = ManageBaseNoteSerializer.Meta.fields + ['target'] + fields = ManageBaseNoteSerializer.Meta.fields + ["target"] class ManageReportSerializer(serializers.ModelSerializer): @@ -701,5 +699,5 @@ class ManageReportSerializer(serializers.ModelSerializer): ] def get_notes(self, o): - notes = getattr(o, '_prefetched_notes', []) + notes = getattr(o, "_prefetched_notes", []) return ManageBaseNoteSerializer(notes, many=True).data diff --git a/api/funkwhale_api/manage/views.py b/api/funkwhale_api/manage/views.py index 38cfef396..898f8307b 100644 --- a/api/funkwhale_api/manage/views.py +++ b/api/funkwhale_api/manage/views.py @@ -470,10 +470,18 @@ class ManageReportViewSet( queryset = ( moderation_models.Report.objects.all() .order_by("-creation_date") - .select_related('submitter', 'target_owner', 'assigned_to', 'target_content_type') - .prefetch_related('target') + .select_related( + "submitter", "target_owner", "assigned_to", "target_content_type" + ) + .prefetch_related("target") .prefetch_related( - Prefetch('notes', queryset=moderation_models.Note.objects.order_by('creation_date').select_related('author'), to_attr="_prefetched_notes") + Prefetch( + "notes", + queryset=moderation_models.Note.objects.order_by( + "creation_date" + ).select_related("author"), + to_attr="_prefetched_notes", + ) ) ) serializer_class = serializers.ManageReportSerializer @@ -491,9 +499,10 @@ class ManageNoteViewSet( ): lookup_field = "uuid" queryset = ( - moderation_models.Note.objects.all().order_by("-creation_date") - .select_related('author', 'target_content_type') - .prefetch_related('target') + moderation_models.Note.objects.all() + .order_by("-creation_date") + .select_related("author", "target_content_type") + .prefetch_related("target") ) serializer_class = serializers.ManageNoteSerializer filterset_class = filters.ManageNoteFilterSet diff --git a/api/funkwhale_api/moderation/models.py b/api/funkwhale_api/moderation/models.py index dc20ae32f..5a4081b7b 100644 --- a/api/funkwhale_api/moderation/models.py +++ b/api/funkwhale_api/moderation/models.py @@ -149,9 +149,7 @@ class Report(federation_models.FederationMixin): target_state = JSONField(null=True) notes = GenericRelation( - "Note", - content_type_field="target_content_type", - object_id_field="target_id", + "Note", content_type_field="target_content_type", object_id_field="target_id" ) def get_federation_id(self): diff --git a/api/funkwhale_api/moderation/serializers.py b/api/funkwhale_api/moderation/serializers.py index f1b6b36b7..fb87f5b9d 100644 --- a/api/funkwhale_api/moderation/serializers.py +++ b/api/funkwhale_api/moderation/serializers.py @@ -1,6 +1,8 @@ +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 @@ -170,6 +172,7 @@ def get_target_owner(target): return mapping[target.__class__](target) + TARGET_CONFIG = { "artist": {"queryset": music_models.Artist.objects.all()}, "album": {"queryset": music_models.Album.objects.all()}, @@ -187,9 +190,7 @@ TARGET_CONFIG = { "get_query": get_actor_query, }, } -TARGET_FIELD = common_fields.GenericRelation( - TARGET_CONFIG -) +TARGET_FIELD = common_fields.GenericRelation(TARGET_CONFIG) class ReportSerializer(serializers.ModelSerializer): @@ -239,6 +240,13 @@ class ReportSerializer(serializers.ModelSerializer): validated_data["target_state"] = target_state_serializer( validated_data["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 = self.fields["target"].to_representation(validated_data["target"]) + validated_data["target_state"]["_target"] = json.loads( + json.dumps(target_data, cls=DjangoJSONEncoder) + ) + if "fid" in validated_data["target_state"]: validated_data["target_state"]["domain"] = urllib.parse.urlparse( validated_data["target_state"]["fid"] diff --git a/api/funkwhale_api/moderation/utils.py b/api/funkwhale_api/moderation/utils.py index 0b2e5bb04..d4a1b879a 100644 --- a/api/funkwhale_api/moderation/utils.py +++ b/api/funkwhale_api/moderation/utils.py @@ -1,4 +1,3 @@ - from rest_framework import serializers from funkwhale_api.federation import models as federation_models diff --git a/api/tests/moderation/test_serializers.py b/api/tests/moderation/test_serializers.py index 37c95c78d..f20f27b2b 100644 --- a/api/tests/moderation/test_serializers.py +++ b/api/tests/moderation/test_serializers.py @@ -1,4 +1,8 @@ +import json import pytest +import urllib.parse + +from django.core.serializers.json import DjangoJSONEncoder from funkwhale_api.common import utils as common_utils from funkwhale_api.federation import models as federation_models @@ -51,7 +55,7 @@ def test_user_filter_serializer_save(factories): ], ) def test_report_serializer_save( - factory_name, target_type, id_field, state_serializer, factories, mocker + factory_name, target_type, id_field, state_serializer, factories, mocker, settings ): target = factories[factory_name]() target_owner = factories["federation.Actor"]() @@ -72,10 +76,21 @@ def test_report_serializer_save( report = serializer.save() + expected_state = state_serializer(target).data + expected_state["_target"] = json.loads( + json.dumps(target_data, cls=DjangoJSONEncoder) + ) + if hasattr(target, "fid"): + expected_state["domain"] = urllib.parse.urlparse(target.fid).hostname + expected_state["is_local"] = ( + expected_state["domain"] == settings.FEDERATION_HOSTNAME + ) + else: + expected_state["is_local"] = True assert report.target == target assert report.type == payload["type"] assert report.summary == payload["summary"] - assert report.target_state == state_serializer(target).data + assert report.target_state == expected_state assert report.target_owner == target_owner get_target_owner.assert_called_once_with(target)