Verified Commit b38cec3f authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Fixed a federation issue related to images

parent 93c371fe
...@@ -31,17 +31,9 @@ class TruncatedCharField(serializers.CharField): ...@@ -31,17 +31,9 @@ class TruncatedCharField(serializers.CharField):
return v return v
class LinkSerializer(jsonld.JsonLdSerializer): class MediaSerializer(jsonld.JsonLdSerializer):
type = serializers.ChoiceField(choices=[contexts.AS.Link, contexts.AS.Image])
href = serializers.URLField(max_length=500)
mediaType = serializers.CharField() mediaType = serializers.CharField()
class Meta:
jsonld_mapping = {
"href": jsonld.first_id(contexts.AS.href),
"mediaType": jsonld.first_val(contexts.AS.mediaType),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.allowed_mimetypes = kwargs.pop("allowed_mimetypes", []) self.allowed_mimetypes = kwargs.pop("allowed_mimetypes", [])
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
...@@ -62,6 +54,43 @@ class LinkSerializer(jsonld.JsonLdSerializer): ...@@ -62,6 +54,43 @@ class LinkSerializer(jsonld.JsonLdSerializer):
) )
class LinkSerializer(MediaSerializer):
type = serializers.ChoiceField(choices=[contexts.AS.Link])
href = serializers.URLField(max_length=500)
class Meta:
jsonld_mapping = {
"href": jsonld.first_id(contexts.AS.href),
"mediaType": jsonld.first_val(contexts.AS.mediaType),
}
class ImageSerializer(MediaSerializer):
type = serializers.ChoiceField(choices=[contexts.AS.Image, contexts.AS.Link])
href = serializers.URLField(max_length=500, required=False)
url = serializers.URLField(max_length=500, required=False)
class Meta:
jsonld_mapping = {
"url": jsonld.first_id(contexts.AS.url),
"href": jsonld.first_id(contexts.AS.href),
"mediaType": jsonld.first_val(contexts.AS.mediaType),
}
def validate(self, data):
validated_data = super().validate(data)
if "url" not in validated_data:
try:
validated_data["url"] = validated_data["href"]
except KeyError:
if self.required:
raise serializers.ValidationError(
"You need to provide a url or href"
)
return validated_data
class EndpointsSerializer(jsonld.JsonLdSerializer): class EndpointsSerializer(jsonld.JsonLdSerializer):
sharedInbox = serializers.URLField(max_length=500, required=False) sharedInbox = serializers.URLField(max_length=500, required=False)
...@@ -95,7 +124,7 @@ class ActorSerializer(jsonld.JsonLdSerializer): ...@@ -95,7 +124,7 @@ class ActorSerializer(jsonld.JsonLdSerializer):
following = serializers.URLField(max_length=500, required=False, allow_null=True) following = serializers.URLField(max_length=500, required=False, allow_null=True)
publicKey = PublicKeySerializer(required=False) publicKey = PublicKeySerializer(required=False)
endpoints = EndpointsSerializer(required=False) endpoints = EndpointsSerializer(required=False)
icon = LinkSerializer( icon = ImageSerializer(
allowed_mimetypes=["image/*"], allow_null=True, required=False allowed_mimetypes=["image/*"], allow_null=True, required=False
) )
...@@ -202,7 +231,7 @@ class ActorSerializer(jsonld.JsonLdSerializer): ...@@ -202,7 +231,7 @@ class ActorSerializer(jsonld.JsonLdSerializer):
common_utils.attach_file( common_utils.attach_file(
actor, actor,
"attachment_icon", "attachment_icon",
{"url": new_value["href"], "mimetype": new_value["mediaType"]} {"url": new_value["url"], "mimetype": new_value["mediaType"]}
if new_value if new_value
else None, else None,
) )
...@@ -853,7 +882,7 @@ def include_image(repr, attachment, field="image"): ...@@ -853,7 +882,7 @@ def include_image(repr, attachment, field="image"):
if attachment: if attachment:
repr[field] = { repr[field] = {
"type": "Image", "type": "Image",
"href": attachment.download_url_original, "url": attachment.download_url_original,
"mediaType": attachment.mimetype or "image/jpeg", "mediaType": attachment.mimetype or "image/jpeg",
} }
else: else:
...@@ -915,14 +944,14 @@ class MusicEntitySerializer(jsonld.JsonLdSerializer): ...@@ -915,14 +944,14 @@ class MusicEntitySerializer(jsonld.JsonLdSerializer):
if ( if (
instance.attachment_cover instance.attachment_cover
and instance.attachment_cover.url == attachment_cover["href"] and instance.attachment_cover.url == attachment_cover["url"]
): ):
# we already have the proper attachment # we already have the proper attachment
return validated_data return validated_data
# create the attachment by hand so it can be attached as the cover # create the attachment by hand so it can be attached as the cover
validated_data["attachment_cover"] = common_models.Attachment.objects.create( validated_data["attachment_cover"] = common_models.Attachment.objects.create(
mimetype=attachment_cover["mediaType"], mimetype=attachment_cover["mediaType"],
url=attachment_cover["href"], url=attachment_cover["url"],
actor=instance.attributed_to, actor=instance.attributed_to,
) )
return validated_data return validated_data
...@@ -938,7 +967,7 @@ class MusicEntitySerializer(jsonld.JsonLdSerializer): ...@@ -938,7 +967,7 @@ class MusicEntitySerializer(jsonld.JsonLdSerializer):
class ArtistSerializer(MusicEntitySerializer): class ArtistSerializer(MusicEntitySerializer):
image = LinkSerializer( image = ImageSerializer(
allowed_mimetypes=["image/*"], allow_null=True, required=False allowed_mimetypes=["image/*"], allow_null=True, required=False
) )
updateable_fields = [ updateable_fields = [
...@@ -982,7 +1011,7 @@ class AlbumSerializer(MusicEntitySerializer): ...@@ -982,7 +1011,7 @@ class AlbumSerializer(MusicEntitySerializer):
released = serializers.DateField(allow_null=True, required=False) released = serializers.DateField(allow_null=True, required=False)
artists = serializers.ListField(child=ArtistSerializer(), min_length=1) artists = serializers.ListField(child=ArtistSerializer(), min_length=1)
# XXX: 1.0 rename to image # XXX: 1.0 rename to image
cover = LinkSerializer( cover = ImageSerializer(
allowed_mimetypes=["image/*"], allow_null=True, required=False allowed_mimetypes=["image/*"], allow_null=True, required=False
) )
updateable_fields = [ updateable_fields = [
...@@ -1045,7 +1074,7 @@ class TrackSerializer(MusicEntitySerializer): ...@@ -1045,7 +1074,7 @@ class TrackSerializer(MusicEntitySerializer):
album = AlbumSerializer() album = AlbumSerializer()
license = serializers.URLField(allow_null=True, required=False) license = serializers.URLField(allow_null=True, required=False)
copyright = serializers.CharField(allow_null=True, required=False) copyright = serializers.CharField(allow_null=True, required=False)
image = LinkSerializer( image = ImageSerializer(
allowed_mimetypes=["image/*"], allow_null=True, required=False allowed_mimetypes=["image/*"], allow_null=True, required=False
) )
......
...@@ -302,7 +302,12 @@ def process_upload(upload, update_denormalization=True): ...@@ -302,7 +302,12 @@ def process_upload(upload, update_denormalization=True):
def get_cover(obj, field): def get_cover(obj, field):
cover = obj.get(field) cover = obj.get(field)
if cover: if cover:
return {"mimetype": cover["mediaType"], "url": cover["href"]} try:
url = cover["url"]
except KeyError:
url = cover["href"]
return {"mimetype": cover["mediaType"], "url": url}
def federation_audio_track_to_metadata(payload, references): def federation_audio_track_to_metadata(payload, references):
......
...@@ -39,7 +39,7 @@ def test_actor_serializer_from_ap(db): ...@@ -39,7 +39,7 @@ def test_actor_serializer_from_ap(db):
"icon": { "icon": {
"type": "Image", "type": "Image",
"mediaType": "image/jpeg", "mediaType": "image/jpeg",
"href": "https://image.example/image.png", "url": "https://image.example/image.png",
}, },
} }
...@@ -65,7 +65,7 @@ def test_actor_serializer_from_ap(db): ...@@ -65,7 +65,7 @@ def test_actor_serializer_from_ap(db):
assert actor.private_key is None assert actor.private_key is None
assert actor.public_key == payload["publicKey"]["publicKeyPem"] assert actor.public_key == payload["publicKey"]["publicKeyPem"]
assert actor.domain_id == "test.federation" assert actor.domain_id == "test.federation"
assert actor.attachment_icon.url == payload["icon"]["href"] assert actor.attachment_icon.url == payload["icon"]["url"]
assert actor.attachment_icon.mimetype == payload["icon"]["mediaType"] assert actor.attachment_icon.mimetype == payload["icon"]["mediaType"]
...@@ -139,7 +139,7 @@ def test_actor_serializer_to_ap(factories): ...@@ -139,7 +139,7 @@ def test_actor_serializer_to_ap(factories):
expected["icon"] = { expected["icon"] = {
"type": "Image", "type": "Image",
"mediaType": "image/jpeg", "mediaType": "image/jpeg",
"href": utils.full_url(ac.attachment_icon.file.url), "url": utils.full_url(ac.attachment_icon.file.url),
} }
serializer = serializers.ActorSerializer(ac) serializer = serializers.ActorSerializer(ac)
...@@ -595,7 +595,7 @@ def test_activity_pub_artist_serializer_to_ap(factories): ...@@ -595,7 +595,7 @@ def test_activity_pub_artist_serializer_to_ap(factories):
"image": { "image": {
"type": "Image", "type": "Image",
"mediaType": "image/jpeg", "mediaType": "image/jpeg",
"href": utils.full_url(artist.attachment_cover.file.url), "url": utils.full_url(artist.attachment_cover.file.url),
}, },
"tag": [ "tag": [
{"type": "Hashtag", "name": "#Punk"}, {"type": "Hashtag", "name": "#Punk"},
...@@ -626,7 +626,7 @@ def test_activity_pub_album_serializer_to_ap(factories): ...@@ -626,7 +626,7 @@ def test_activity_pub_album_serializer_to_ap(factories):
"image": { "image": {
"type": "Image", "type": "Image",
"mediaType": "image/jpeg", "mediaType": "image/jpeg",
"href": utils.full_url(album.attachment_cover.file.url), "url": utils.full_url(album.attachment_cover.file.url),
}, },
"musicbrainzId": album.mbid, "musicbrainzId": album.mbid,
"published": album.creation_date.isoformat(), "published": album.creation_date.isoformat(),
...@@ -661,7 +661,7 @@ def test_activity_pub_artist_serializer_from_ap_update(factories, faker): ...@@ -661,7 +661,7 @@ def test_activity_pub_artist_serializer_from_ap_update(factories, faker):
"attributedTo": artist.attributed_to.fid, "attributedTo": artist.attributed_to.fid,
"mediaType": "text/html", "mediaType": "text/html",
"content": common_utils.render_html(faker.sentence(), "text/html"), "content": common_utils.render_html(faker.sentence(), "text/html"),
"image": {"type": "Image", "mediaType": "image/jpeg", "href": faker.url()}, "image": {"type": "Image", "mediaType": "image/jpeg", "url": faker.url()},
"tag": [ "tag": [
{"type": "Hashtag", "name": "#Punk"}, {"type": "Hashtag", "name": "#Punk"},
{"type": "Hashtag", "name": "#Rock"}, {"type": "Hashtag", "name": "#Rock"},
...@@ -677,7 +677,7 @@ def test_activity_pub_artist_serializer_from_ap_update(factories, faker): ...@@ -677,7 +677,7 @@ def test_activity_pub_artist_serializer_from_ap_update(factories, faker):
assert artist.name == payload["name"] assert artist.name == payload["name"]
assert str(artist.mbid) == payload["musicbrainzId"] assert str(artist.mbid) == payload["musicbrainzId"]
assert artist.attachment_cover.url == payload["image"]["href"] assert artist.attachment_cover.url == payload["image"]["url"]
assert artist.attachment_cover.mimetype == payload["image"]["mediaType"] assert artist.attachment_cover.mimetype == payload["image"]["mediaType"]
assert artist.description.text == payload["content"] assert artist.description.text == payload["content"]
assert artist.description.content_type == "text/html" assert artist.description.content_type == "text/html"
...@@ -767,7 +767,7 @@ def test_activity_pub_track_serializer_to_ap(factories): ...@@ -767,7 +767,7 @@ def test_activity_pub_track_serializer_to_ap(factories):
"image": { "image": {
"type": "Image", "type": "Image",
"mediaType": "image/jpeg", "mediaType": "image/jpeg",
"href": utils.full_url(track.attachment_cover.file.url), "url": utils.full_url(track.attachment_cover.file.url),
}, },
} }
serializer = serializers.TrackSerializer(track) serializer = serializers.TrackSerializer(track)
...@@ -797,8 +797,8 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker): ...@@ -797,8 +797,8 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker):
"content": "Hello there", "content": "Hello there",
"attributedTo": track_attributed_to.fid, "attributedTo": track_attributed_to.fid,
"image": { "image": {
"type": "Link", "type": "Image",
"href": "https://cover.image/track.png", "url": "https://cover.image/track.png",
"mediaType": "image/png", "mediaType": "image/png",
}, },
"album": { "album": {
...@@ -829,8 +829,8 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker): ...@@ -829,8 +829,8 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker):
"attributedTo": album_artist_attributed_to.fid, "attributedTo": album_artist_attributed_to.fid,
"tag": [{"type": "Hashtag", "name": "AlbumArtistTag"}], "tag": [{"type": "Hashtag", "name": "AlbumArtistTag"}],
"image": { "image": {
"type": "Link", "type": "Image",
"href": "https://cover.image/album-artist.png", "url": "https://cover.image/album-artist.png",
"mediaType": "image/png", "mediaType": "image/png",
}, },
} }
...@@ -848,8 +848,8 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker): ...@@ -848,8 +848,8 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker):
"published": published.isoformat(), "published": published.isoformat(),
"tag": [{"type": "Hashtag", "name": "ArtistTag"}], "tag": [{"type": "Hashtag", "name": "ArtistTag"}],
"image": { "image": {
"type": "Link", "type": "Image",
"href": "https://cover.image/artist.png", "url": "https://cover.image/artist.png",
"mediaType": "image/png", "mediaType": "image/png",
}, },
} }
...@@ -877,7 +877,7 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker): ...@@ -877,7 +877,7 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker):
assert str(track.mbid) == data["musicbrainzId"] assert str(track.mbid) == data["musicbrainzId"]
assert track.description.text == data["content"] assert track.description.text == data["content"]
assert track.description.content_type == "text/html" assert track.description.content_type == "text/html"
assert track.attachment_cover.url == data["image"]["href"] assert track.attachment_cover.url == data["image"]["url"]
assert track.attachment_cover.mimetype == data["image"]["mediaType"] assert track.attachment_cover.mimetype == data["image"]["mediaType"]
assert album.from_activity == activity assert album.from_activity == activity
...@@ -900,7 +900,7 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker): ...@@ -900,7 +900,7 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker):
assert artist.attributed_to == artist_attributed_to assert artist.attributed_to == artist_attributed_to
assert artist.description.text == data["artists"][0]["content"] assert artist.description.text == data["artists"][0]["content"]
assert artist.description.content_type == data["artists"][0]["mediaType"] assert artist.description.content_type == data["artists"][0]["mediaType"]
assert artist.attachment_cover.url == data["artists"][0]["image"]["href"] assert artist.attachment_cover.url == data["artists"][0]["image"]["url"]
assert artist.attachment_cover.mimetype == data["artists"][0]["image"]["mediaType"] assert artist.attachment_cover.mimetype == data["artists"][0]["image"]["mediaType"]
assert album_artist.from_activity == activity assert album_artist.from_activity == activity
...@@ -915,8 +915,7 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker): ...@@ -915,8 +915,7 @@ def test_activity_pub_track_serializer_from_ap(factories, r_mock, mocker):
== data["album"]["artists"][0]["mediaType"] == data["album"]["artists"][0]["mediaType"]
) )
assert ( assert (
album_artist.attachment_cover.url album_artist.attachment_cover.url == data["album"]["artists"][0]["image"]["url"]
== data["album"]["artists"][0]["image"]["href"]
) )
assert ( assert (
album_artist.attachment_cover.mimetype album_artist.attachment_cover.mimetype
...@@ -949,7 +948,7 @@ def test_activity_pub_track_serializer_from_ap_update(factories, r_mock, mocker, ...@@ -949,7 +948,7 @@ def test_activity_pub_track_serializer_from_ap_update(factories, r_mock, mocker,
"attributedTo": track_attributed_to.fid, "attributedTo": track_attributed_to.fid,
"album": serializers.AlbumSerializer(track.album).data, "album": serializers.AlbumSerializer(track.album).data,
"artists": [serializers.ArtistSerializer(track.artist).data], "artists": [serializers.ArtistSerializer(track.artist).data],
"image": {"type": "Link", "mediaType": "image/jpeg", "href": faker.url()}, "image": {"type": "Image", "mediaType": "image/jpeg", "url": faker.url()},
"tag": [ "tag": [
{"type": "Hashtag", "name": "#Hello"}, {"type": "Hashtag", "name": "#Hello"},
# Ensure we can handle tags without a leading # # Ensure we can handle tags without a leading #
...@@ -970,7 +969,7 @@ def test_activity_pub_track_serializer_from_ap_update(factories, r_mock, mocker, ...@@ -970,7 +969,7 @@ def test_activity_pub_track_serializer_from_ap_update(factories, r_mock, mocker,
assert track.description.content_type == "text/html" assert track.description.content_type == "text/html"
assert track.description.text == "hello there" assert track.description.text == "hello there"
assert str(track.mbid) == data["musicbrainzId"] assert str(track.mbid) == data["musicbrainzId"]
assert track.attachment_cover.url == data["image"]["href"] assert track.attachment_cover.url == data["image"]["url"]
assert track.attachment_cover.mimetype == data["image"]["mediaType"] assert track.attachment_cover.mimetype == data["image"]["mediaType"]
set_tags.assert_called_once_with(track, *["Hello", "World"]) set_tags.assert_called_once_with(track, *["Hello", "World"])
...@@ -1159,7 +1158,7 @@ def test_local_actor_serializer_to_ap(factories): ...@@ -1159,7 +1158,7 @@ def test_local_actor_serializer_to_ap(factories):
expected["icon"] = { expected["icon"] = {
"type": "Image", "type": "Image",
"mediaType": "image/jpeg", "mediaType": "image/jpeg",
"href": utils.full_url(ac.attachment_icon.file.url), "url": utils.full_url(ac.attachment_icon.file.url),
} }
serializer = serializers.ActorSerializer(ac) serializer = serializers.ActorSerializer(ac)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment