Skip to content
Snippets Groups Projects
Verified Commit 0e652103 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Merge branch 'master' into develop

parents 8f261f96 d5cb412a
No related branches found
No related tags found
No related merge requests found
...@@ -10,7 +10,7 @@ This changelog is viewable on the web at https://docs.funkwhale.audio/changelog. ...@@ -10,7 +10,7 @@ This changelog is viewable on the web at https://docs.funkwhale.audio/changelog.
.. towncrier .. towncrier
0.19.1 (2018-06-28) 0.19.1 (2019-06-28)
------------------- -------------------
Upgrade instructions are available at Upgrade instructions are available at
......
...@@ -10,7 +10,7 @@ def populate_domains(apps, schema_editor): ...@@ -10,7 +10,7 @@ def populate_domains(apps, schema_editor):
Actor = apps.get_model("federation", "Actor") Actor = apps.get_model("federation", "Actor")
domains = set( domains = set(
[v.lower() for v in Actor.objects.values_list("old_domain", flat=True)] [v.lower() for v in Actor.objects.values_list("old_domain", flat=True) if v]
) )
for domain in sorted(domains): for domain in sorted(domains):
print("Populating domain {}...".format(domain)) print("Populating domain {}...".format(domain))
......
...@@ -14,8 +14,6 @@ from funkwhale_api.music import tasks as music_tasks ...@@ -14,8 +14,6 @@ from funkwhale_api.music import tasks as music_tasks
from . import activity, actors, contexts, jsonld, models, tasks, utils from . import activity, actors, contexts, jsonld, models, tasks, utils
AP_CONTEXT = jsonld.get_default_context()
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -116,7 +114,7 @@ class ActorSerializer(jsonld.JsonLdSerializer): ...@@ -116,7 +114,7 @@ class ActorSerializer(jsonld.JsonLdSerializer):
if instance.manually_approves_followers is not None: if instance.manually_approves_followers is not None:
ret["manuallyApprovesFollowers"] = instance.manually_approves_followers ret["manuallyApprovesFollowers"] = instance.manually_approves_followers
ret["@context"] = AP_CONTEXT ret["@context"] = jsonld.get_default_context()
if instance.public_key: if instance.public_key:
ret["publicKey"] = { ret["publicKey"] = {
"owner": instance.fid, "owner": instance.fid,
...@@ -324,7 +322,7 @@ class FollowSerializer(serializers.Serializer): ...@@ -324,7 +322,7 @@ class FollowSerializer(serializers.Serializer):
def to_representation(self, instance): def to_representation(self, instance):
return { return {
"@context": AP_CONTEXT, "@context": jsonld.get_default_context(),
"actor": instance.actor.fid, "actor": instance.actor.fid,
"id": instance.get_federation_id(), "id": instance.get_federation_id(),
"object": instance.target.fid, "object": instance.target.fid,
...@@ -396,7 +394,7 @@ class AcceptFollowSerializer(serializers.Serializer): ...@@ -396,7 +394,7 @@ class AcceptFollowSerializer(serializers.Serializer):
actor = instance.target actor = instance.target
return { return {
"@context": AP_CONTEXT, "@context": jsonld.get_default_context(),
"id": instance.get_federation_id() + "/accept", "id": instance.get_federation_id() + "/accept",
"type": "Accept", "type": "Accept",
"actor": actor.fid, "actor": actor.fid,
...@@ -450,7 +448,7 @@ class UndoFollowSerializer(serializers.Serializer): ...@@ -450,7 +448,7 @@ class UndoFollowSerializer(serializers.Serializer):
def to_representation(self, instance): def to_representation(self, instance):
return { return {
"@context": AP_CONTEXT, "@context": jsonld.get_default_context(),
"id": instance.get_federation_id() + "/undo", "id": instance.get_federation_id() + "/undo",
"type": "Undo", "type": "Undo",
"actor": instance.actor.fid, "actor": instance.actor.fid,
...@@ -530,7 +528,7 @@ class ActivitySerializer(serializers.Serializer): ...@@ -530,7 +528,7 @@ class ActivitySerializer(serializers.Serializer):
d.update(conf) d.update(conf)
if self.context.get("include_ap_context", True): if self.context.get("include_ap_context", True):
d["@context"] = AP_CONTEXT d["@context"] = jsonld.get_default_context()
return d return d
...@@ -624,7 +622,7 @@ class PaginatedCollectionSerializer(jsonld.JsonLdSerializer): ...@@ -624,7 +622,7 @@ class PaginatedCollectionSerializer(jsonld.JsonLdSerializer):
} }
d.update(get_additional_fields(conf)) d.update(get_additional_fields(conf))
if self.context.get("include_ap_context", True): if self.context.get("include_ap_context", True):
d["@context"] = AP_CONTEXT d["@context"] = jsonld.get_default_context()
return d return d
...@@ -771,7 +769,7 @@ class CollectionPageSerializer(jsonld.JsonLdSerializer): ...@@ -771,7 +769,7 @@ class CollectionPageSerializer(jsonld.JsonLdSerializer):
) )
d.update(get_additional_fields(conf)) d.update(get_additional_fields(conf))
if self.context.get("include_ap_context", True): if self.context.get("include_ap_context", True):
d["@context"] = AP_CONTEXT d["@context"] = jsonld.get_default_context()
return d return d
...@@ -828,7 +826,7 @@ class ArtistSerializer(MusicEntitySerializer): ...@@ -828,7 +826,7 @@ class ArtistSerializer(MusicEntitySerializer):
} }
if self.context.get("include_ap_context", self.parent is None): if self.context.get("include_ap_context", self.parent is None):
d["@context"] = AP_CONTEXT d["@context"] = jsonld.get_default_context()
return d return d
...@@ -883,7 +881,7 @@ class AlbumSerializer(MusicEntitySerializer): ...@@ -883,7 +881,7 @@ class AlbumSerializer(MusicEntitySerializer):
or "image/jpeg", or "image/jpeg",
} }
if self.context.get("include_ap_context", self.parent is None): if self.context.get("include_ap_context", self.parent is None):
d["@context"] = AP_CONTEXT d["@context"] = jsonld.get_default_context()
return d return d
...@@ -946,7 +944,7 @@ class TrackSerializer(MusicEntitySerializer): ...@@ -946,7 +944,7 @@ class TrackSerializer(MusicEntitySerializer):
} }
if self.context.get("include_ap_context", self.parent is None): if self.context.get("include_ap_context", self.parent is None):
d["@context"] = AP_CONTEXT d["@context"] = jsonld.get_default_context()
return d return d
def create(self, validated_data): def create(self, validated_data):
...@@ -1106,7 +1104,7 @@ class UploadSerializer(jsonld.JsonLdSerializer): ...@@ -1106,7 +1104,7 @@ class UploadSerializer(jsonld.JsonLdSerializer):
d["updated"] = instance.modification_date.isoformat() d["updated"] = instance.modification_date.isoformat()
if self.context.get("include_ap_context", self.parent is None): if self.context.get("include_ap_context", self.parent is None):
d["@context"] = AP_CONTEXT d["@context"] = jsonld.get_default_context()
return d return d
......
# Test dependencies go here. # Test dependencies go here.
flake8 flake8
pytest pytest>=5
# pytest-django until a new release containing django_assert_num_queries pytest-django>=3.5.1
# is deployed to pypi
git+https://github.com/pytest-dev/pytest-django.git@d3d9bb3ef6f0377cb5356eb368992a0834692378
pytest-mock pytest-mock
pytest-sugar pytest-sugar
pytest-xdist pytest-xdist
pytest-cov pytest-cov
pytest-env pytest-env
requests-mock requests-mock
pytest-randomly
pytest-profiling<1.4 pytest-profiling<1.4
...@@ -72,9 +72,10 @@ def test_library_follow_serializer_do_not_allow_own_library(factories): ...@@ -72,9 +72,10 @@ def test_library_follow_serializer_do_not_allow_own_library(factories):
library = factories["music.Library"](actor=actor) library = factories["music.Library"](actor=actor)
serializer = api_serializers.LibraryFollowSerializer(context={"actor": actor}) serializer = api_serializers.LibraryFollowSerializer(context={"actor": actor})
with pytest.raises(api_serializers.serializers.ValidationError) as e: with pytest.raises(
api_serializers.serializers.ValidationError, match=r".*own library.*"
):
serializer.validate_target(library) serializer.validate_target(library)
assert "own library" in str(e)
def test_manage_upload_action_read(factories): def test_manage_upload_action_read(factories):
......
...@@ -132,13 +132,13 @@ def test_expand_remote_doc(r_mock): ...@@ -132,13 +132,13 @@ def test_expand_remote_doc(r_mock):
async def test_fetch_many(a_responses): async def test_fetch_many(a_responses):
doc = { doc = {
"@context": ["https://www.w3.org/ns/activitystreams", {}], "@context": jsonld.get_default_context(),
"id": "https://noop/federation/actors/demo", "id": "https://noop/federation/actors/demo",
"type": "Person", "type": "Person",
"followers": "https://noop/federation/actors/demo/followers", "followers": "https://noop/federation/actors/demo/followers",
} }
followers_doc = { followers_doc = {
"@context": ["https://www.w3.org/ns/activitystreams", {}], "@context": jsonld.get_default_context(),
"id": "https://noop/federation/actors/demo/followers", "id": "https://noop/federation/actors/demo/followers",
"type": "Collection", "type": "Collection",
} }
...@@ -152,13 +152,13 @@ async def test_fetch_many(a_responses): ...@@ -152,13 +152,13 @@ async def test_fetch_many(a_responses):
def test_dereference(): def test_dereference():
followers_doc = { followers_doc = {
"@context": ["https://www.w3.org/ns/activitystreams", {}], "@context": jsonld.get_default_context(),
"id": "https://noop/federation/actors/demo/followers", "id": "https://noop/federation/actors/demo/followers",
"type": "Collection", "type": "Collection",
} }
actor_doc = { actor_doc = {
"@context": ["https://www.w3.org/ns/activitystreams", {}], "@context": jsonld.get_default_context(),
"id": "https://noop/federation/actors/demo", "id": "https://noop/federation/actors/demo",
"type": "Person", "type": "Person",
"followers": "https://noop/federation/actors/demo/followers", "followers": "https://noop/federation/actors/demo/followers",
...@@ -281,7 +281,7 @@ def test_jsonld_serializer_fallback(): ...@@ -281,7 +281,7 @@ def test_jsonld_serializer_fallback():
} }
payload = { payload = {
"@context": ["https://www.w3.org/ns/activitystreams", {}], "@context": jsonld.get_default_context(),
"id": "https://noop.url/federation/actors/demo", "id": "https://noop.url/federation/actors/demo",
"type": "Person", "type": "Person",
"name": "Hello", "name": "Hello",
...@@ -313,14 +313,14 @@ def test_jsonld_serializer_dereference(a_responses): ...@@ -313,14 +313,14 @@ def test_jsonld_serializer_dereference(a_responses):
} }
payload = { payload = {
"@context": ["https://www.w3.org/ns/activitystreams", {}], "@context": jsonld.get_default_context(),
"id": "https://noop.url/federation/actors/demo", "id": "https://noop.url/federation/actors/demo",
"type": "Person", "type": "Person",
"followers": "https://noop.url/federation/actors/demo/followers", "followers": "https://noop.url/federation/actors/demo/followers",
} }
followers_doc = { followers_doc = {
"@context": ["https://www.w3.org/ns/activitystreams", {}], "@context": jsonld.get_default_context(),
"id": "https://noop.url/federation/actors/demo/followers", "id": "https://noop.url/federation/actors/demo/followers",
"type": "Collection", "type": "Collection",
} }
......
...@@ -5,13 +5,19 @@ def test_domain_14_migration(migrator): ...@@ -5,13 +5,19 @@ def test_domain_14_migration(migrator):
old_apps = migrator.loader.project_state([(a, f)]).apps old_apps = migrator.loader.project_state([(a, f)]).apps
Actor = old_apps.get_model(a, "Actor") Actor = old_apps.get_model(a, "Actor")
a1 = Actor.objects.create( a1 = Actor.objects.create(
fid="http://test1.com", preferred_username="test1", old_domain="dOmaiN1.com" fid="http://testmigration1.com",
preferred_username="test1",
old_domain="dOmaiN1.com",
) )
a2 = Actor.objects.create( a2 = Actor.objects.create(
fid="http://test2.com", preferred_username="test2", old_domain="domain1.com" fid="http://testmigration2.com",
preferred_username="test2",
old_domain="domain1.com",
) )
a3 = Actor.objects.create( a3 = Actor.objects.create(
fid="http://test3.com", preferred_username="test2", old_domain="domain2.com" fid="http://testmigration3.com",
preferred_username="test2",
old_domain="domain2.com",
) )
migrator.loader.build_graph() migrator.loader.build_graph()
......
...@@ -561,7 +561,7 @@ def test_music_library_serializer_from_private(factories, mocker): ...@@ -561,7 +561,7 @@ def test_music_library_serializer_from_private(factories, mocker):
def test_activity_pub_artist_serializer_to_ap(factories): def test_activity_pub_artist_serializer_to_ap(factories):
artist = factories["music.Artist"](attributed=True) artist = factories["music.Artist"](attributed=True)
expected = { expected = {
"@context": serializers.AP_CONTEXT, "@context": jsonld.get_default_context(),
"type": "Artist", "type": "Artist",
"id": artist.fid, "id": artist.fid,
"name": artist.name, "name": artist.name,
...@@ -578,7 +578,7 @@ def test_activity_pub_album_serializer_to_ap(factories): ...@@ -578,7 +578,7 @@ def test_activity_pub_album_serializer_to_ap(factories):
album = factories["music.Album"](attributed=True) album = factories["music.Album"](attributed=True)
expected = { expected = {
"@context": serializers.AP_CONTEXT, "@context": jsonld.get_default_context(),
"type": "Album", "type": "Album",
"id": album.fid, "id": album.fid,
"name": album.title, "name": album.title,
...@@ -607,7 +607,7 @@ def test_activity_pub_track_serializer_to_ap(factories): ...@@ -607,7 +607,7 @@ def test_activity_pub_track_serializer_to_ap(factories):
license="cc-by-4.0", copyright="test", disc_number=3, attributed=True license="cc-by-4.0", copyright="test", disc_number=3, attributed=True
) )
expected = { expected = {
"@context": serializers.AP_CONTEXT, "@context": jsonld.get_default_context(),
"published": track.creation_date.isoformat(), "published": track.creation_date.isoformat(),
"type": "Track", "type": "Track",
"musicbrainzId": track.mbid, "musicbrainzId": track.mbid,
...@@ -737,7 +737,7 @@ def test_activity_pub_upload_serializer_from_ap(factories, mocker, r_mock): ...@@ -737,7 +737,7 @@ def test_activity_pub_upload_serializer_from_ap(factories, mocker, r_mock):
updated = timezone.now() updated = timezone.now()
released = timezone.now().date() released = timezone.now().date()
data = { data = {
"@context": serializers.AP_CONTEXT, "@context": jsonld.get_default_context(),
"type": "Audio", "type": "Audio",
"id": "https://track.file", "id": "https://track.file",
"name": "Ignored", "name": "Ignored",
...@@ -825,7 +825,7 @@ def test_activity_pub_audio_serializer_to_ap(factories): ...@@ -825,7 +825,7 @@ def test_activity_pub_audio_serializer_to_ap(factories):
mimetype="audio/mp3", bitrate=42, duration=43, size=44 mimetype="audio/mp3", bitrate=42, duration=43, size=44
) )
expected = { expected = {
"@context": serializers.AP_CONTEXT, "@context": jsonld.get_default_context(),
"type": "Audio", "type": "Audio",
"id": upload.fid, "id": upload.fid,
"name": upload.track.full_name, "name": upload.track.full_name,
......
...@@ -11,22 +11,21 @@ DATA_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "files") ...@@ -11,22 +11,21 @@ DATA_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "files")
def test_management_command_requires_a_valid_library_id(factories): def test_management_command_requires_a_valid_library_id(factories):
path = os.path.join(DATA_DIR, "dummy_file.ogg") path = os.path.join(DATA_DIR, "dummy_file.ogg")
with pytest.raises(CommandError) as e: with pytest.raises(CommandError, match=r".*Invalid library id.*"):
call_command("import_files", "wrong_id", path, interactive=False) call_command("import_files", "wrong_id", path, interactive=False)
assert "Invalid library id" in str(e)
def test_in_place_import_only_from_music_dir(factories, settings): def test_in_place_import_only_from_music_dir(factories, settings):
library = factories["music.Library"](actor__local=True) library = factories["music.Library"](actor__local=True)
settings.MUSIC_DIRECTORY_PATH = "/nope" settings.MUSIC_DIRECTORY_PATH = "/nope"
path = os.path.join(DATA_DIR, "dummy_file.ogg") path = os.path.join(DATA_DIR, "dummy_file.ogg")
with pytest.raises(CommandError) as e: with pytest.raises(
CommandError, match=r".*Importing in-place only works if importing.*"
):
call_command( call_command(
"import_files", str(library.uuid), path, in_place=True, interactive=False "import_files", str(library.uuid), path, in_place=True, interactive=False
) )
assert "Importing in-place only works if importing" in str(e)
def test_import_with_multiple_argument(factories, mocker): def test_import_with_multiple_argument(factories, mocker):
library = factories["music.Library"](actor__local=True) library = factories["music.Library"](actor__local=True)
......
Fixed broken URL to artist and album on album and track pages (#871)
...@@ -192,7 +192,7 @@ export default { ...@@ -192,7 +192,7 @@ export default {
subtitle () { subtitle () {
let route = this.$router.resolve({name: 'library.artists.detail', params: {id: this.object.artist.id }}) let route = this.$router.resolve({name: 'library.artists.detail', params: {id: this.object.artist.id }})
let msg = this.$npgettext('Content/Album/Header.Title', 'Album containing %{ count } track, by <a class="internal" href="%{ artistUrl }">%{ artist }</a>', 'Album containing %{ count } tracks, by <a class="internal" href="%{ artistUrl }">%{ artist }</a>', this.object.tracks.length) let msg = this.$npgettext('Content/Album/Header.Title', 'Album containing %{ count } track, by <a class="internal" href="%{ artistUrl }">%{ artist }</a>', 'Album containing %{ count } tracks, by <a class="internal" href="%{ artistUrl }">%{ artist }</a>', this.object.tracks.length)
return this.$gettextInterpolate(msg, {count: this.object.tracks.length, artist: this.object.artist.name, artistUrl: route.location.path}) return this.$gettextInterpolate(msg, {count: this.object.tracks.length, artist: this.object.artist.name, artistUrl: route.href})
} }
}, },
watch: { watch: {
......
...@@ -210,11 +210,11 @@ export default { ...@@ -210,11 +210,11 @@ export default {
}, },
albumUrl () { albumUrl () {
let route = this.$router.resolve({name: 'library.albums.detail', params: {id: this.track.album.id }}) let route = this.$router.resolve({name: 'library.albums.detail', params: {id: this.track.album.id }})
return route.location.path return route.href
}, },
artistUrl () { artistUrl () {
let route = this.$router.resolve({name: 'library.artists.detail', params: {id: this.track.artist.id }}) let route = this.$router.resolve({name: 'library.artists.detail', params: {id: this.track.artist.id }})
return route.location.path return route.href
}, },
headerStyle() { headerStyle() {
if (!this.cover) { if (!this.cover) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment