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,
|
|
},
|
|
},
|
|
)
|