Browse Source

feat: add atomic assign-items endpoints for video and podcast playlists and update author ordering

master
Mohsen Taba 3 weeks ago
parent
commit
840f996f5a
  1. 17
      apps/library/migrations/0009_alter_author_options.py
  2. 2
      apps/library/models.py
  3. 2
      apps/library/views.py
  4. 2
      apps/library/views_admin.py
  5. 36
      apps/podcast/views_admin.py
  6. 36
      apps/video/views_admin.py

17
apps/library/migrations/0009_alter_author_options.py

@ -0,0 +1,17 @@
# Generated by Django 4.2.30 on 2026-08-27 11:03
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('library', '0008_alter_author_slug_alter_book_slug_and_more'),
]
operations = [
migrations.AlterModelOptions(
name='author',
options={'ordering': ['-created_at', '-id'], 'verbose_name': 'Author', 'verbose_name_plural': 'Authors'},
),
]

2
apps/library/models.py

@ -122,7 +122,7 @@ class Author(LowercaseSlugMixin, models.Model):
class Meta:
verbose_name = _('Author')
verbose_name_plural = _('Authors')
ordering = ['full_name', 'id']
ordering = ['-created_at', '-id']
def __str__(self):
return self.full_name

2
apps/library/views.py

@ -268,7 +268,7 @@ class AuthorListView(ListAPIView):
def get_queryset(self):
return Author.objects.annotate(
books_count_annotation=Count('books', filter=Q(books__status=True))
).order_by('full_name', 'id')
).order_by('-created_at', '-id')
class AuthorDetailView(RetrieveAPIView):

2
apps/library/views_admin.py

@ -133,7 +133,7 @@ class AdminAuthorViewSet(ModelViewSet):
| Q(slug__icontains=search_query)
)
return queryset.order_by("full_name", "id")
return queryset.order_by("-created_at", "-id")
@action(detail=True, methods=["post"], url_path="assign-books")
def assign_books(self, request, pk=None):

36
apps/podcast/views_admin.py

@ -211,3 +211,39 @@ class AdminPodcastPlaylistViewSet(ModelViewSet):
context={"request": request},
)
return Response(serializer.data)
@action(detail=True, methods=["post"], url_path="assign-items")
def assign_items(self, request, pk=None):
playlist = self.get_object()
add_ids = request.data.get("add_ids", []) or request.data.get("podcast_ids", []) or request.data.get("item_ids", [])
remove_ids = request.data.get("remove_ids", [])
with transaction.atomic():
if remove_ids:
playlist.playlist_items.filter(id__in=remove_ids).delete()
if add_ids:
existing_podcast_ids = set(playlist.playlist_items.values_list("podcast_id", flat=True))
new_podcast_ids = [pid for pid in add_ids if pid not in existing_podcast_ids]
current_count = playlist.playlist_items.count()
new_items = [
PlaylistItem(
playlist=playlist,
podcast_id=pid,
priority=current_count + idx + 1,
)
for idx, pid in enumerate(new_podcast_ids)
]
if new_items:
PlaylistItem.objects.bulk_create(new_items)
playlist.total_time = playlist.calculate_total_time()
playlist.save(update_fields=["total_time"])
serializer = AdminPodcastPlaylistItemSerializer(
playlist.playlist_items.select_related("podcast").order_by("priority", "id"),
many=True,
context={"request": request},
)
return Response(serializer.data, status=status.HTTP_200_OK)

36
apps/video/views_admin.py

@ -208,3 +208,39 @@ class AdminVideoPlaylistViewSet(ModelViewSet):
context={"request": request},
)
return Response(serializer.data)
@action(detail=True, methods=["post"], url_path="assign-items")
def assign_items(self, request, pk=None):
playlist = self.get_object()
add_ids = request.data.get("add_ids", []) or request.data.get("video_ids", []) or request.data.get("item_ids", [])
remove_ids = request.data.get("remove_ids", [])
with transaction.atomic():
if remove_ids:
playlist.playlist_items.filter(id__in=remove_ids).delete()
if add_ids:
existing_video_ids = set(playlist.playlist_items.values_list("video_id", flat=True))
new_video_ids = [vid for vid in add_ids if vid not in existing_video_ids]
current_count = playlist.playlist_items.count()
new_items = [
PlaylistItem(
playlist=playlist,
video_id=vid,
priority=current_count + idx + 1,
)
for idx, vid in enumerate(new_video_ids)
]
if new_items:
PlaylistItem.objects.bulk_create(new_items)
playlist.total_time = playlist.calculate_total_time()
playlist.save(update_fields=["total_time"])
serializer = AdminVideoPlaylistItemSerializer(
playlist.playlist_items.select_related("video").order_by("priority", "id"),
many=True,
context={"request": request},
)
return Response(serializer.data, status=status.HTTP_200_OK)
Loading…
Cancel
Save