feat: Enhance favorites functionality; add favorites filtering to playlists and sounds, and improve favorite indicators in responses

This commit is contained in:
JSC
2025-08-16 21:41:50 +02:00
parent 78508c84eb
commit f906b6d643
10 changed files with 97 additions and 52 deletions

View File

@@ -3,9 +3,7 @@
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlmodel.ext.asyncio.session import AsyncSession
from app.core.database import get_db
from app.core.dependencies import get_current_active_user
from app.models.user import User
from app.schemas.common import MessageResponse
@@ -35,7 +33,7 @@ async def get_user_favorites(
) -> FavoritesListResponse:
"""Get all favorites for the current user."""
favorites = await favorite_service.get_user_favorites(
current_user.id, limit, offset
current_user.id, limit, offset,
)
return FavoritesListResponse(favorites=favorites)
@@ -49,7 +47,7 @@ async def get_user_sound_favorites(
) -> FavoritesListResponse:
"""Get sound favorites for the current user."""
favorites = await favorite_service.get_user_sound_favorites(
current_user.id, limit, offset
current_user.id, limit, offset,
)
return FavoritesListResponse(favorites=favorites)
@@ -63,7 +61,7 @@ async def get_user_playlist_favorites(
) -> FavoritesListResponse:
"""Get playlist favorites for the current user."""
favorites = await favorite_service.get_user_playlist_favorites(
current_user.id, limit, offset
current_user.id, limit, offset,
)
return FavoritesListResponse(favorites=favorites)
@@ -94,16 +92,15 @@ async def add_sound_favorite(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(e),
) from e
elif "already favorited" in str(e):
if "already favorited" in str(e):
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=str(e),
) from e
else:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
) from e
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
) from e
@router.post("/playlists/{playlist_id}", response_model=FavoriteResponse)
@@ -115,7 +112,7 @@ async def add_playlist_favorite(
"""Add a playlist to favorites."""
try:
favorite = await favorite_service.add_playlist_favorite(
current_user.id, playlist_id
current_user.id, playlist_id,
)
return FavoriteResponse.model_validate(favorite)
except ValueError as e:
@@ -124,16 +121,15 @@ async def add_playlist_favorite(
status_code=status.HTTP_404_NOT_FOUND,
detail=str(e),
) from e
elif "already favorited" in str(e):
if "already favorited" in str(e):
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail=str(e),
) from e
else:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
) from e
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e),
) from e
@router.delete("/sounds/{sound_id}", response_model=MessageResponse)
@@ -189,6 +185,6 @@ async def check_playlist_favorited(
) -> dict[str, bool]:
"""Check if a playlist is favorited by the current user."""
is_favorited = await favorite_service.is_playlist_favorited(
current_user.id, playlist_id
current_user.id, playlist_id,
)
return {"is_favorited": is_favorited}

View File

@@ -40,8 +40,9 @@ def get_favorite_service() -> FavoriteService:
@router.get("/")
async def get_all_playlists( # noqa: PLR0913
current_user: Annotated[User, Depends(get_current_active_user_flexible)], # noqa: ARG001
current_user: Annotated[User, Depends(get_current_active_user_flexible)],
playlist_service: Annotated[PlaylistService, Depends(get_playlist_service)],
favorite_service: Annotated[FavoriteService, Depends(get_favorite_service)],
search: Annotated[
str | None,
Query(description="Search playlists by name"),
@@ -62,9 +63,13 @@ async def get_all_playlists( # noqa: PLR0913
int,
Query(description="Number of results to skip", ge=0),
] = 0,
) -> list[dict]:
favorites_only: Annotated[
bool,
Query(description="Show only favorited playlists"),
] = False,
) -> list[PlaylistResponse]:
"""Get all playlists from all users with search and sorting."""
return await playlist_service.search_and_sort_playlists(
playlists = await playlist_service.search_and_sort_playlists(
search_query=search,
sort_by=sort_by,
sort_order=sort_order,
@@ -72,8 +77,29 @@ async def get_all_playlists( # noqa: PLR0913
include_stats=True,
limit=limit,
offset=offset,
favorites_only=favorites_only,
current_user_id=current_user.id,
)
# Convert to PlaylistResponse with favorite indicators
playlist_responses = []
for playlist_dict in playlists:
# The playlist service returns dict, need to create playlist object-like structure
is_favorited = await favorite_service.is_playlist_favorited(current_user.id, playlist_dict["id"])
favorite_count = await favorite_service.get_playlist_favorite_count(playlist_dict["id"])
# Create a PlaylistResponse-like dict with proper datetime conversion
playlist_response = {
**playlist_dict,
"created_at": playlist_dict["created_at"].isoformat() if playlist_dict["created_at"] else None,
"updated_at": playlist_dict["updated_at"].isoformat() if playlist_dict["updated_at"] else None,
"is_favorited": is_favorited,
"favorite_count": favorite_count,
}
playlist_responses.append(playlist_response)
return playlist_responses
@router.get("/user")
async def get_user_playlists(
@@ -83,7 +109,7 @@ async def get_user_playlists(
) -> list[PlaylistResponse]:
"""Get playlists for the current user only."""
playlists = await playlist_service.get_user_playlists(current_user.id)
# Add favorite indicators for each playlist
playlist_responses = []
for playlist in playlists:
@@ -91,7 +117,7 @@ async def get_user_playlists(
favorite_count = await favorite_service.get_playlist_favorite_count(playlist.id)
playlist_response = PlaylistResponse.from_playlist(playlist, is_favorited, favorite_count)
playlist_responses.append(playlist_response)
return playlist_responses

View File

@@ -8,7 +8,6 @@ from sqlmodel.ext.asyncio.session import AsyncSession
from app.core.database import get_db, get_session_factory
from app.core.dependencies import get_current_active_user_flexible
from app.models.credit_action import CreditActionType
from app.models.sound import Sound
from app.models.user import User
from app.repositories.sound import SortOrder, SoundRepository, SoundSortField
from app.schemas.sound import SoundResponse, SoundsListResponse
@@ -87,7 +86,7 @@ async def get_sounds( # noqa: PLR0913
favorites_only=favorites_only,
user_id=current_user.id,
)
# Add favorite indicators for each sound
sound_responses = []
for sound in sounds:
@@ -95,7 +94,7 @@ async def get_sounds( # noqa: PLR0913
favorite_count = await favorite_service.get_sound_favorite_count(sound.id)
sound_response = SoundResponse.from_sound(sound, is_favorited, favorite_count)
sound_responses.append(sound_response)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,