mirror of
https://code.eliotberriot.com/funkwhale/funkwhale.git
synced 2025-10-05 21:12:11 +02:00
0.17 release documentation initial draft and migration script
This commit is contained in:
parent
98591b2ac4
commit
b6e376ed0a
14 changed files with 683 additions and 106 deletions
|
@ -2,6 +2,8 @@ import pytest
|
|||
|
||||
from funkwhale_api.common import scripts
|
||||
from funkwhale_api.common.management.commands import script
|
||||
from funkwhale_api.federation import models as federation_models
|
||||
from funkwhale_api.music import models as music_models
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -44,29 +46,216 @@ def test_django_permissions_to_user_permissions(factories, command):
|
|||
assert user2.permission_federation is True
|
||||
|
||||
|
||||
@pytest.mark.skip("Refactoring in progress")
|
||||
def test_migrate_to_user_libraries(factories, command):
|
||||
user1 = factories["users.User"](is_superuser=False, with_actor=True)
|
||||
user2 = factories["users.User"](is_superuser=True, with_actor=True)
|
||||
factories["users.User"](is_superuser=True)
|
||||
no_import_files = factories["music.Upload"].create_batch(size=5, library=None)
|
||||
import_jobs = factories["music.ImportJob"].create_batch(
|
||||
batch__submitted_by=user1, size=5, finished=True
|
||||
@pytest.mark.parametrize(
|
||||
"open_api,expected_visibility", [(True, "everyone"), (False, "instance")]
|
||||
)
|
||||
def test_migrate_to_user_libraries_create_libraries(
|
||||
factories, open_api, expected_visibility, stdout
|
||||
):
|
||||
user1 = factories["users.User"](with_actor=True)
|
||||
user2 = factories["users.User"](with_actor=True)
|
||||
|
||||
result = scripts.migrate_to_user_libraries.create_libraries(open_api, stdout)
|
||||
|
||||
user1_library = user1.actor.libraries.get(
|
||||
name="default", privacy_level=expected_visibility
|
||||
)
|
||||
# we delete libraries that are created automatically
|
||||
for j in import_jobs:
|
||||
j.upload.library = None
|
||||
j.upload.save()
|
||||
user2_library = user2.actor.libraries.get(
|
||||
name="default", privacy_level=expected_visibility
|
||||
)
|
||||
|
||||
assert result == {user1.pk: user1_library.pk, user2.pk: user2_library.pk}
|
||||
|
||||
|
||||
def test_migrate_to_user_libraries_update_uploads(factories, stdout):
|
||||
user1 = factories["users.User"](with_actor=True)
|
||||
user2 = factories["users.User"](with_actor=True)
|
||||
|
||||
library1 = factories["music.Library"](actor=user1.actor)
|
||||
library2 = factories["music.Library"](actor=user2.actor)
|
||||
|
||||
upload1 = factories["music.Upload"]()
|
||||
upload2 = factories["music.Upload"]()
|
||||
|
||||
# we delete libraries
|
||||
upload1.library = None
|
||||
upload2.library = None
|
||||
upload1.save()
|
||||
upload2.save()
|
||||
|
||||
factories["music.ImportJob"](batch__submitted_by=user1, upload=upload1)
|
||||
factories["music.ImportJob"](batch__submitted_by=user2, upload=upload2)
|
||||
|
||||
libraries_by_user = {user1.pk: library1.pk, user2.pk: library2.pk}
|
||||
|
||||
scripts.migrate_to_user_libraries.update_uploads(libraries_by_user, stdout)
|
||||
|
||||
upload1.refresh_from_db()
|
||||
upload2.refresh_from_db()
|
||||
|
||||
assert upload1.library == library1
|
||||
assert upload1.import_status == "finished"
|
||||
assert upload2.library == library2
|
||||
assert upload2.import_status == "finished"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"open_api,expected_visibility", [(True, "everyone"), (False, "instance")]
|
||||
)
|
||||
def test_migrate_to_user_libraries_without_jobs(
|
||||
factories, open_api, expected_visibility, stdout
|
||||
):
|
||||
superuser = factories["users.User"](is_superuser=True, with_actor=True)
|
||||
upload1 = factories["music.Upload"]()
|
||||
upload2 = factories["music.Upload"]()
|
||||
upload3 = factories["music.Upload"](audio_file=None)
|
||||
|
||||
# we delete libraries
|
||||
upload1.library = None
|
||||
upload2.library = None
|
||||
upload3.library = None
|
||||
upload1.save()
|
||||
upload2.save()
|
||||
upload3.save()
|
||||
|
||||
factories["music.ImportJob"](upload=upload2)
|
||||
scripts.migrate_to_user_libraries.update_orphan_uploads(open_api, stdout)
|
||||
|
||||
upload1.refresh_from_db()
|
||||
upload2.refresh_from_db()
|
||||
upload3.refresh_from_db()
|
||||
|
||||
superuser_library = superuser.actor.libraries.get(
|
||||
name="default", privacy_level=expected_visibility
|
||||
)
|
||||
assert upload1.library == superuser_library
|
||||
assert upload1.import_status == "finished"
|
||||
# left untouched because they don't match filters
|
||||
assert upload2.library is None
|
||||
assert upload3.library is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"model,args,path",
|
||||
[
|
||||
("music.Upload", {"library__actor__local": True}, "/federation/music/uploads/"),
|
||||
("music.Artist", {}, "/federation/music/artists/"),
|
||||
("music.Album", {}, "/federation/music/albums/"),
|
||||
("music.Track", {}, "/federation/music/tracks/"),
|
||||
],
|
||||
)
|
||||
def test_migrate_to_user_libraries_generate_fids(
|
||||
factories, args, model, path, settings, stdout
|
||||
):
|
||||
template = "{}{}{}"
|
||||
|
||||
objects = factories[model].create_batch(5, fid=None, **args)
|
||||
klass = factories[model]._meta.model
|
||||
|
||||
# we leave a fid on the first one, and set the others to None
|
||||
existing_fid = objects[0].fid
|
||||
base_path = existing_fid.replace(str(objects[0].uuid), "")
|
||||
klass.objects.filter(pk__in=[o.pk for o in objects[1:]]).update(fid=None)
|
||||
|
||||
scripts.migrate_to_user_libraries.set_fid(klass.objects.all(), path, stdout)
|
||||
|
||||
for i, o in enumerate(objects):
|
||||
o.refresh_from_db()
|
||||
if i == 0:
|
||||
assert o.fid == existing_fid
|
||||
else:
|
||||
assert o.fid == template.format(settings.FUNKWHALE_URL, path, o.uuid)
|
||||
# we also ensure the path we insert match the one that is generated
|
||||
# by the app on objects creation, as a safe guard for typos
|
||||
assert base_path == o.fid.replace(str(o.uuid), "")
|
||||
|
||||
|
||||
def test_migrate_to_user_libraries_update_actors_shared_inbox_url(factories, stdout):
|
||||
local = factories["federation.Actor"](local=True, shared_inbox_url=None)
|
||||
remote = factories["federation.Actor"](local=False, shared_inbox_url=None)
|
||||
expected = federation_models.get_shared_inbox_url()
|
||||
scripts.migrate_to_user_libraries.update_shared_inbox_url(stdout)
|
||||
|
||||
local.refresh_from_db()
|
||||
remote.refresh_from_db()
|
||||
|
||||
assert local.shared_inbox_url == expected
|
||||
assert remote.shared_inbox_url is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("part", ["following", "followers"])
|
||||
def test_migrate_to_user_libraries_generate_actor_urls(
|
||||
factories, part, settings, stdout
|
||||
):
|
||||
field = "{}_url".format(part)
|
||||
ok = factories["users.User"]().create_actor()
|
||||
local = factories["federation.Actor"](local=True, **{field: None})
|
||||
remote = factories["federation.Actor"](local=False, **{field: None})
|
||||
|
||||
assert getattr(local, field) is None
|
||||
expected = "{}/federation/actors/{}/{}".format(
|
||||
settings.FUNKWHALE_URL, local.preferred_username, part
|
||||
)
|
||||
ok_url = getattr(ok, field)
|
||||
|
||||
scripts.migrate_to_user_libraries.generate_actor_urls(part, stdout)
|
||||
|
||||
ok.refresh_from_db()
|
||||
local.refresh_from_db()
|
||||
remote.refresh_from_db()
|
||||
|
||||
# unchanged
|
||||
assert getattr(ok, field) == ok_url
|
||||
assert getattr(remote, field) is None
|
||||
|
||||
assert getattr(local, field) == expected
|
||||
assert expected.replace(local.preferred_username, "") == ok_url.replace(
|
||||
ok.preferred_username, ""
|
||||
)
|
||||
|
||||
|
||||
def test_migrate_to_users_libraries_command(
|
||||
preferences, mocker, db, command, queryset_equal_queries
|
||||
):
|
||||
preferences["common__api_authentication_required"] = False
|
||||
open_api = not preferences["common__api_authentication_required"]
|
||||
create_libraries = mocker.patch.object(
|
||||
scripts.migrate_to_user_libraries,
|
||||
"create_libraries",
|
||||
return_value={"hello": "world"},
|
||||
)
|
||||
update_uploads = mocker.patch.object(
|
||||
scripts.migrate_to_user_libraries, "update_uploads"
|
||||
)
|
||||
update_orphan_uploads = mocker.patch.object(
|
||||
scripts.migrate_to_user_libraries, "update_orphan_uploads"
|
||||
)
|
||||
set_fid = mocker.patch.object(scripts.migrate_to_user_libraries, "set_fid")
|
||||
update_shared_inbox_url = mocker.patch.object(
|
||||
scripts.migrate_to_user_libraries, "update_shared_inbox_url"
|
||||
)
|
||||
generate_actor_urls = mocker.patch.object(
|
||||
scripts.migrate_to_user_libraries, "generate_actor_urls"
|
||||
)
|
||||
|
||||
scripts.migrate_to_user_libraries.main(command)
|
||||
|
||||
# tracks with import jobs are bound to the importer's library
|
||||
library = user1.actor.libraries.get(name="default")
|
||||
assert list(library.uploads.order_by("id").values_list("id", flat=True)) == sorted(
|
||||
[ij.upload.pk for ij in import_jobs]
|
||||
)
|
||||
create_libraries.assert_called_once_with(open_api, command.stdout)
|
||||
update_uploads.assert_called_once_with({"hello": "world"}, command.stdout)
|
||||
update_orphan_uploads.assert_called_once_with(open_api, command.stdout)
|
||||
set_fid_params = [
|
||||
(
|
||||
music_models.Upload.objects.exclude(library__actor__user=None),
|
||||
"/federation/music/uploads/",
|
||||
),
|
||||
(music_models.Artist.objects.all(), "/federation/music/artists/"),
|
||||
(music_models.Album.objects.all(), "/federation/music/albums/"),
|
||||
(music_models.Track.objects.all(), "/federation/music/tracks/"),
|
||||
]
|
||||
for qs, path in set_fid_params:
|
||||
set_fid.assert_any_call(qs, path, command.stdout)
|
||||
update_shared_inbox_url.assert_called_once_with(command.stdout)
|
||||
# generate_actor_urls(part, stdout):
|
||||
|
||||
# tracks without import jobs are bound to first superuser
|
||||
library = user2.actor.libraries.get(name="default")
|
||||
assert list(library.uploads.order_by("id").values_list("id", flat=True)) == sorted(
|
||||
[upload.pk for upload in no_import_files]
|
||||
)
|
||||
for part in ["followers", "following"]:
|
||||
generate_actor_urls.assert_any_call(part, command.stdout)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue