From e561ea2cbd8eec83fcc45a624855a39a3a84441d Mon Sep 17 00:00:00 2001 From: Georg Krause Date: Thu, 11 Jan 2024 14:39:26 +0000 Subject: [PATCH] feat: Implement upload groups --- api/config/urls/api_v2.py | 2 ++ .../music/migrations/0058_uploadgroup.py | 32 +++++++++++++++++++ api/funkwhale_api/music/models.py | 5 +++ api/funkwhale_api/music/serializers.py | 12 +++++++ api/funkwhale_api/music/views.py | 7 ++++ api/tests/music/test_urls.py | 6 ++++ api/tests/music/test_views.py | 30 +++++++++++++++++ 7 files changed, 94 insertions(+) create mode 100644 api/funkwhale_api/music/migrations/0058_uploadgroup.py create mode 100644 api/tests/music/test_urls.py diff --git a/api/config/urls/api_v2.py b/api/config/urls/api_v2.py index 1a2c05625..9a29dcc1a 100644 --- a/api/config/urls/api_v2.py +++ b/api/config/urls/api_v2.py @@ -2,10 +2,12 @@ from django.conf.urls import include from django.urls import re_path from funkwhale_api.common import routers as common_routers +from funkwhale_api.music.views import UploadGroupViewSet from . import api router = common_routers.OptionalSlashRouter() +router.register(r"upload-groups", UploadGroupViewSet, "upload-groups") v2_patterns = router.urls v2_patterns += [ diff --git a/api/funkwhale_api/music/migrations/0058_uploadgroup.py b/api/funkwhale_api/music/migrations/0058_uploadgroup.py new file mode 100644 index 000000000..449415560 --- /dev/null +++ b/api/funkwhale_api/music/migrations/0058_uploadgroup.py @@ -0,0 +1,32 @@ +# Generated by Django 3.2.23 on 2024-01-11 14:34 + +import datetime +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + dependencies = [ + ("music", "0057_auto_20221118_2108"), + ] + + operations = [ + migrations.CreateModel( + name="UploadGroup", + fields=[ + ( + "name", + models.CharField(default=datetime.datetime.now, max_length=255), + ), + ( + "guid", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + ), + ), + ], + ), + ] diff --git a/api/funkwhale_api/music/models.py b/api/funkwhale_api/music/models.py index 3587b92a4..28bada018 100644 --- a/api/funkwhale_api/music/models.py +++ b/api/funkwhale_api/music/models.py @@ -1558,3 +1558,8 @@ def update_request_status(sender, instance, created, **kwargs): # let's mark the request as imported since the import is over instance.import_request.status = "imported" return instance.import_request.save(update_fields=["status"]) + + +class UploadGroup(models.Model): + name = models.CharField(max_length=255, default=datetime.datetime.now) + guid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) diff --git a/api/funkwhale_api/music/serializers.py b/api/funkwhale_api/music/serializers.py index cf550524b..2dcb1a081 100644 --- a/api/funkwhale_api/music/serializers.py +++ b/api/funkwhale_api/music/serializers.py @@ -907,3 +907,15 @@ class SearchResultSerializer(serializers.Serializer): tracks = TrackSerializer(many=True) albums = AlbumSerializer(many=True) tags = tags_serializers.TagSerializer(many=True) + + +class UploadGroupSerializer(serializers.ModelSerializer): + class Meta: + model = models.UploadGroup + fields = "__all__" + + name = serializers.CharField(required=False) + uploadUrl = serializers.SerializerMethodField(read_only=True) + + def get_uploadUrl(self, value): + return f"{settings.FUNKWHALE_URL}/api/v2/upload-groups/{value.guid}/uploads" diff --git a/api/funkwhale_api/music/views.py b/api/funkwhale_api/music/views.py index 9a4c19103..2af208d89 100644 --- a/api/funkwhale_api/music/views.py +++ b/api/funkwhale_api/music/views.py @@ -969,3 +969,10 @@ class OembedView(views.APIView): serializer.is_valid(raise_exception=True) embed_data = serializer.save() return Response(embed_data) + + +class UploadGroupViewSet(viewsets.ModelViewSet): + permission_classes = [oauth_permissions.ScopePermission] + required_scope = "libraries" + queryset = models.UploadGroup.objects.all() + serializer_class = serializers.UploadGroupSerializer diff --git a/api/tests/music/test_urls.py b/api/tests/music/test_urls.py new file mode 100644 index 000000000..103531653 --- /dev/null +++ b/api/tests/music/test_urls.py @@ -0,0 +1,6 @@ +from django.urls import reverse + + +def test_can_resolve_upload_urls(): + url = reverse("api:v2:upload-groups-list") + assert url == "/api/v2/upload-groups" diff --git a/api/tests/music/test_views.py b/api/tests/music/test_views.py index b128a240e..50b257066 100644 --- a/api/tests/music/test_views.py +++ b/api/tests/music/test_views.py @@ -1589,3 +1589,33 @@ def test_can_patch_upload_list(factories, logged_in_api_client): assert response.status_code == 200 assert upload.library.privacy_level == "everyone" + + +def test_can_create_upload_group_without_name(logged_in_api_client): + count = models.UploadGroup.objects.count() + + url = reverse("api:v2:upload-groups-list") + response = logged_in_api_client.post(url) + + assert response.status_code == 201 + assert count + 1 == models.UploadGroup.objects.count() + assert response.data.get("guid") != "" + assert response.data.get("name") != "" + assert "https://test.federation/api/v2/upload-groups/" in response.data.get( + "uploadUrl" + ) + + +def test_can_create_upload_group_with_name(logged_in_api_client): + count = models.UploadGroup.objects.count() + + url = reverse("api:v2:upload-groups-list") + response = logged_in_api_client.post(url, {"name": "Test Name"}) + + assert response.status_code == 201 + assert count + 1 == models.UploadGroup.objects.count() + assert response.data.get("guid") != "" + assert response.data.get("name") == "Test Name" + assert "https://test.federation/api/v2/upload-groups/" in response.data.get( + "uploadUrl" + )