feat: Assign upload groups to existing and news v1 uploads
This commit is contained in:
parent
e169df2e6e
commit
3677b5db8f
|
@ -57,6 +57,7 @@ class UploadAdmin(admin.ModelAdmin):
|
|||
"size",
|
||||
"bitrate",
|
||||
"import_status",
|
||||
"upload_group",
|
||||
]
|
||||
list_select_related = ["track"]
|
||||
search_fields = [
|
||||
|
@ -69,6 +70,11 @@ class UploadAdmin(admin.ModelAdmin):
|
|||
list_filter = ["mimetype", "import_status", "library__privacy_level"]
|
||||
|
||||
|
||||
@admin.register(models.UploadGroup)
|
||||
class UploadGroupAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
|
||||
@admin.register(models.UploadVersion)
|
||||
class UploadVersionAdmin(admin.ModelAdmin):
|
||||
list_display = [
|
||||
|
|
|
@ -164,6 +164,14 @@ class TrackFactory(
|
|||
license = factory.PostGeneration(_license_post_generation)
|
||||
|
||||
|
||||
@registry.register
|
||||
class UploadGroupFactory(factory.django.DjangoModelFactory):
|
||||
name = factory.Faker("name")
|
||||
|
||||
class Meta:
|
||||
model = "music.UploadGroup"
|
||||
|
||||
|
||||
@registry.register
|
||||
class UploadFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
|
||||
fid = factory.Faker("federation_url")
|
||||
|
@ -172,6 +180,7 @@ class UploadFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
|
|||
audio_file = factory.django.FileField(
|
||||
from_path=os.path.join(SAMPLES_PATH, "test.ogg")
|
||||
)
|
||||
upload_group = factory.SubFactory(UploadGroupFactory)
|
||||
|
||||
bitrate = None
|
||||
size = None
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 3.2.23 on 2024-01-15 10:55
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("music", "0058_uploadgroup"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="upload",
|
||||
name="upload_group",
|
||||
field=models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="uploads",
|
||||
to="music.uploadgroup",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 3.2.23 on 2024-01-15 10:55
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def populate_upload_groups(apps, schema_editor):
|
||||
upload = apps.get_model("music", "Upload")
|
||||
upload_group = apps.get_model("music", "UploadGroup")
|
||||
for upload in upload.objects.all():
|
||||
group, _ = upload_group.objects.get_or_create(name=upload.import_reference)
|
||||
upload.upload_group = group
|
||||
upload.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("music", "0059_upload_upload_group"),
|
||||
]
|
||||
|
||||
operations = [migrations.RunPython(populate_upload_groups)]
|
|
@ -0,0 +1,22 @@
|
|||
# Generated by Django 3.2.23 on 2024-01-15 11:00
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("music", "0060_auto_20240115_1055"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="upload",
|
||||
name="upload_group",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="uploads",
|
||||
to="music.uploadgroup",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -738,6 +738,9 @@ class Upload(models.Model):
|
|||
related_name="uploads",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
upload_group = models.ForeignKey(
|
||||
"UploadGroup", related_name="uploads", on_delete=models.CASCADE
|
||||
)
|
||||
|
||||
# metadata from federation
|
||||
metadata = JSONField(
|
||||
|
@ -754,6 +757,7 @@ class Upload(models.Model):
|
|||
)
|
||||
# a short reference provided by the client to group multiple files
|
||||
# in the same import
|
||||
# TODO DEPRECATED This can be removed when APIv1 gets removed or fully replace by import_group.name
|
||||
import_reference = models.CharField(max_length=50, default=get_import_reference)
|
||||
|
||||
# optional metadata about import results (error messages, etc.)
|
||||
|
@ -1434,5 +1438,17 @@ def update_request_status(sender, instance, created, **kwargs):
|
|||
|
||||
|
||||
class UploadGroup(models.Model):
|
||||
"""
|
||||
Upload groups are supposed to bundle uploads in order to make it easier to keep an overview
|
||||
|
||||
Attributes
|
||||
----------
|
||||
name A name that can be selected by the user
|
||||
guid A globally unique identifier to reference the group
|
||||
"""
|
||||
|
||||
name = models.CharField(max_length=255, default=datetime.datetime.now)
|
||||
guid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
|
|
@ -790,7 +790,11 @@ class UploadViewSet(
|
|||
return context
|
||||
|
||||
def perform_create(self, serializer):
|
||||
upload = serializer.save()
|
||||
group_name = serializer.validated_data.get("import_reference") or str(
|
||||
datetime.datetime.date(datetime.datetime.now())
|
||||
)
|
||||
upload_group, _ = models.UploadGroup.objects.get_or_create(name=group_name)
|
||||
upload = serializer.save(upload_group=upload_group)
|
||||
if upload.import_status == "pending":
|
||||
common_utils.on_commit(tasks.process_upload.delay, upload_id=upload.pk)
|
||||
|
||||
|
|
|
@ -810,6 +810,56 @@ def test_user_can_create_upload(logged_in_api_client, factories, mocker, audio_f
|
|||
m.assert_called_once_with(tasks.process_upload.delay, upload_id=upload.pk)
|
||||
|
||||
|
||||
def test_upload_creates_implicit_upload_group(
|
||||
logged_in_api_client, factories, mocker, audio_file
|
||||
):
|
||||
library = factories["music.Library"](actor__user=logged_in_api_client.user)
|
||||
url = reverse("api:v1:uploads-list")
|
||||
upload_group_count = models.UploadGroup.objects.count()
|
||||
|
||||
response = logged_in_api_client.post(
|
||||
url,
|
||||
{
|
||||
"audio_file": audio_file,
|
||||
"source": "upload://test",
|
||||
"library": library.uuid,
|
||||
"import_metadata": '{"title": "foo"}',
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
assert upload_group_count + 1 == models.UploadGroup.objects.count()
|
||||
assert (
|
||||
models.UploadGroup.objects.filter(
|
||||
name=str(datetime.datetime.date(datetime.datetime.now()))
|
||||
).count()
|
||||
== 1
|
||||
)
|
||||
|
||||
|
||||
def test_upload_creates_named_upload_group(
|
||||
logged_in_api_client, factories, mocker, audio_file
|
||||
):
|
||||
library = factories["music.Library"](actor__user=logged_in_api_client.user)
|
||||
url = reverse("api:v1:uploads-list")
|
||||
upload_group_count = models.UploadGroup.objects.count()
|
||||
|
||||
response = logged_in_api_client.post(
|
||||
url,
|
||||
{
|
||||
"audio_file": audio_file,
|
||||
"source": "upload://test",
|
||||
"import_reference": "test",
|
||||
"library": library.uuid,
|
||||
"import_metadata": '{"title": "foo"}',
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
assert upload_group_count + 1 == models.UploadGroup.objects.count()
|
||||
assert models.UploadGroup.objects.filter(name="test").count() == 1
|
||||
|
||||
|
||||
def test_user_can_create_upload_in_channel(
|
||||
logged_in_api_client, factories, mocker, audio_file
|
||||
):
|
||||
|
|
Loading…
Reference in New Issue