259 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			259 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Python
		
	
	
	
| import json
 | |
| import urllib.parse
 | |
| 
 | |
| import pytest
 | |
| 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
 | |
| from funkwhale_api.moderation import serializers, signals
 | |
| 
 | |
| 
 | |
| def test_user_filter_serializer_repr(factories):
 | |
|     artist = factories["music.Artist"]()
 | |
|     content_filter = factories["moderation.UserFilter"](target_artist=artist)
 | |
| 
 | |
|     expected = {
 | |
|         "uuid": str(content_filter.uuid),
 | |
|         "target": {"type": "artist", "id": artist.pk, "name": artist.name},
 | |
|         "creation_date": content_filter.creation_date.isoformat().replace(
 | |
|             "+00:00", "Z"
 | |
|         ),
 | |
|     }
 | |
| 
 | |
|     serializer = serializers.UserFilterSerializer(content_filter)
 | |
| 
 | |
|     assert serializer.data == expected
 | |
| 
 | |
| 
 | |
| def test_user_filter_serializer_save(factories):
 | |
|     artist = factories["music.Artist"]()
 | |
|     user = factories["users.User"]()
 | |
|     data = {"target": {"type": "artist", "id": artist.pk}}
 | |
| 
 | |
|     serializer = serializers.UserFilterSerializer(data=data)
 | |
|     serializer.is_valid(raise_exception=True)
 | |
|     content_filter = serializer.save(user=user)
 | |
| 
 | |
|     assert content_filter.target_artist == artist
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     "factory_name, target_type, id_field, state_serializer",
 | |
|     [
 | |
|         ("music.Artist", "artist", "id", serializers.ArtistStateSerializer),
 | |
|         ("music.Album", "album", "id", serializers.AlbumStateSerializer),
 | |
|         ("music.Track", "track", "id", serializers.TrackStateSerializer),
 | |
|         ("music.Library", "library", "uuid", serializers.LibraryStateSerializer),
 | |
|         (
 | |
|             "federation.Actor",
 | |
|             "account",
 | |
|             "full_username",
 | |
|             serializers.ActorStateSerializer,
 | |
|         ),
 | |
|         ("audio.Channel", "channel", "uuid", serializers.ChannelStateSerializer),
 | |
|     ],
 | |
| )
 | |
| def test_report_federated_entity_serializer_save(
 | |
|     factory_name, target_type, id_field, state_serializer, factories, mocker, settings
 | |
| ):
 | |
|     target = factories[factory_name]()
 | |
|     target_owner = factories["federation.Actor"]()
 | |
|     submitter = factories["federation.Actor"]()
 | |
|     target_data = {"type": target_type, id_field: getattr(target, id_field)}
 | |
|     payload = {
 | |
|         "summary": "Report content",
 | |
|         "type": "illegal_content",
 | |
|         "target": target_data,
 | |
|     }
 | |
|     serializer = serializers.ReportSerializer(
 | |
|         data=payload, context={"submitter": submitter}
 | |
|     )
 | |
|     get_target_owner = mocker.patch.object(
 | |
|         serializers, "get_target_owner", return_value=target_owner
 | |
|     )
 | |
|     assert serializer.is_valid(raise_exception=True) is True
 | |
| 
 | |
|     report = serializer.save()
 | |
| 
 | |
|     expected_state = state_serializer(target).data
 | |
|     expected_state["_target"] = json.loads(
 | |
|         json.dumps(target_data, cls=DjangoJSONEncoder)
 | |
|     )
 | |
|     expected_state["domain"] = urllib.parse.urlparse(target.fid).hostname
 | |
|     expected_state["is_local"] = (
 | |
|         expected_state["domain"] == settings.FEDERATION_HOSTNAME
 | |
|     )
 | |
| 
 | |
|     assert report.target == target
 | |
|     assert report.type == payload["type"]
 | |
|     assert report.summary == payload["summary"]
 | |
|     assert report.target_state == expected_state
 | |
|     assert report.target_owner == target_owner
 | |
|     get_target_owner.assert_called_once_with(target)
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     "factory_name, target_type, id_field, state_serializer",
 | |
|     [("playlists.Playlist", "playlist", "id", serializers.PlaylistStateSerializer)],
 | |
| )
 | |
| def test_report_local_entity_serializer_save(
 | |
|     factory_name, target_type, id_field, state_serializer, factories, mocker, settings
 | |
| ):
 | |
|     target = factories[factory_name]()
 | |
|     target_owner = factories["federation.Actor"]()
 | |
|     submitter = factories["federation.Actor"]()
 | |
|     target_data = {"type": target_type, id_field: getattr(target, id_field)}
 | |
|     payload = {
 | |
|         "summary": "Report content",
 | |
|         "type": "illegal_content",
 | |
|         "target": target_data,
 | |
|     }
 | |
|     serializer = serializers.ReportSerializer(
 | |
|         data=payload, context={"submitter": submitter}
 | |
|     )
 | |
|     get_target_owner = mocker.patch.object(
 | |
|         serializers, "get_target_owner", return_value=target_owner
 | |
|     )
 | |
|     assert serializer.is_valid(raise_exception=True) is True
 | |
| 
 | |
|     report = serializer.save()
 | |
| 
 | |
|     expected_state = state_serializer(target).data
 | |
|     expected_state["_target"] = json.loads(
 | |
|         json.dumps(target_data, cls=DjangoJSONEncoder)
 | |
|     )
 | |
|     expected_state["is_local"] = True
 | |
|     assert report.target == target
 | |
|     assert report.type == payload["type"]
 | |
|     assert report.summary == payload["summary"]
 | |
|     assert report.target_state == expected_state
 | |
|     assert report.target_owner == target_owner
 | |
|     get_target_owner.assert_called_once_with(target)
 | |
| 
 | |
| 
 | |
| def test_report_serializer_save_anonymous(factories, mocker):
 | |
|     target = factories["music.Artist"]()
 | |
|     payload = {
 | |
|         "summary": "Report content",
 | |
|         "type": "illegal_content",
 | |
|         "target": {"type": "artist", "id": target.pk},
 | |
|         "submitter_email": "test@submitter.example",
 | |
|     }
 | |
|     serializer = serializers.ReportSerializer(data=payload)
 | |
| 
 | |
|     assert serializer.is_valid(raise_exception=True) is True
 | |
| 
 | |
|     report = serializer.save()
 | |
| 
 | |
|     assert report.target == target
 | |
|     assert report.type == payload["type"]
 | |
|     assert report.summary == payload["summary"]
 | |
|     assert report.submitter_email == payload["submitter_email"]
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     "factory_name, factory_kwargs, owner_field",
 | |
|     [
 | |
|         ("music.Artist", {"attributed": True}, "attributed_to"),
 | |
|         ("music.Album", {"attributed": True}, "attributed_to"),
 | |
|         ("music.Track", {"attributed": True}, "attributed_to"),
 | |
|         ("music.Library", {}, "actor"),
 | |
|         ("playlists.Playlist", {}, "actor"),
 | |
|         ("federation.Actor", {}, "self"),
 | |
|         ("audio.Channel", {}, "attributed_to"),
 | |
|     ],
 | |
| )
 | |
| def test_get_target_owner(factory_name, factory_kwargs, owner_field, factories):
 | |
|     target = factories[factory_name](**factory_kwargs)
 | |
|     if owner_field == "self":
 | |
|         expected_owner = target
 | |
|     else:
 | |
|         expected_owner = common_utils.recursive_getattr(target, owner_field)
 | |
| 
 | |
|     assert isinstance(expected_owner, federation_models.Actor)
 | |
|     assert serializers.get_target_owner(target) == expected_owner
 | |
| 
 | |
| 
 | |
| def test_report_serializer_repr(factories, to_api_date):
 | |
|     target = factories["music.Artist"]()
 | |
|     report = factories["moderation.Report"](target=target)
 | |
|     expected = {
 | |
|         "uuid": str(report.uuid),
 | |
|         "summary": report.summary,
 | |
|         "type": report.type,
 | |
|         "target": {"type": "artist", "id": target.pk},
 | |
|         "creation_date": to_api_date(report.creation_date),
 | |
|         "handled_date": None,
 | |
|         "is_handled": False,
 | |
|         "submitter_email": None,
 | |
|     }
 | |
|     serializer = serializers.ReportSerializer(report)
 | |
|     assert serializer.data == expected
 | |
| 
 | |
| 
 | |
| @pytest.mark.parametrize(
 | |
|     "preference, context, payload, is_valid",
 | |
|     [
 | |
|         # anonymous reports not enabled for the category
 | |
|         (
 | |
|             ["illegal_content"],
 | |
|             {},
 | |
|             {"type": "other", "submitter_email": "hello@example.test"},
 | |
|             False,
 | |
|         ),
 | |
|         # anonymous reports enabled for the category, but invalid e-mail
 | |
|         (["other"], {}, {"type": "other", "submitter_email": "hello@"}, False),
 | |
|         # anonymous reports enabled for the category, no e-mail
 | |
|         (["other"], {}, {"type": "other"}, False),
 | |
|         # anonymous reports enabled for the category, actor object is empty
 | |
|         (["other"], {"submitter": None}, {"type": "other"}, False),
 | |
|         # valid examples
 | |
|         (
 | |
|             ["other"],
 | |
|             {},
 | |
|             {"type": "other", "submitter_email": "hello@example.test"},
 | |
|             True,
 | |
|         ),
 | |
|     ],
 | |
| )
 | |
| def test_report_serializer_save_unauthenticated_validation(
 | |
|     preference, context, payload, is_valid, factories, preferences
 | |
| ):
 | |
|     preferences["moderation__unauthenticated_report_types"] = preference
 | |
|     target = factories["music.Artist"]()
 | |
|     target_data = {"type": "artist", "id": target.id}
 | |
|     payload["summary"] = "Test"
 | |
|     payload["target"] = target_data
 | |
|     serializer = serializers.ReportSerializer(data=payload, context=context)
 | |
|     assert serializer.is_valid() is is_valid
 | |
| 
 | |
| 
 | |
| def test_report_create_send_websocket_event(factories, mocker):
 | |
|     target = factories["music.Artist"]()
 | |
|     group_send = mocker.patch("funkwhale_api.common.channels.group_send")
 | |
|     report_created = mocker.spy(signals.report_created, "send")
 | |
|     payload = {
 | |
|         "summary": "Report content",
 | |
|         "type": "illegal_content",
 | |
|         "target": {"type": "artist", "id": target.pk},
 | |
|         "submitter_email": "test@submitter.example",
 | |
|     }
 | |
|     serializer = serializers.ReportSerializer(data=payload)
 | |
| 
 | |
|     assert serializer.is_valid(raise_exception=True) is True
 | |
|     report = serializer.save()
 | |
|     report_created.assert_called_once_with(sender=None, report=report)
 | |
|     group_send.assert_called_with(
 | |
|         "admin.moderation",
 | |
|         {
 | |
|             "type": "event.send",
 | |
|             "text": "",
 | |
|             "data": {
 | |
|                 "type": "report.created",
 | |
|                 "report": serializer.data,
 | |
|                 "unresolved_count": 1,
 | |
|             },
 | |
|         },
 | |
|     )
 |