refactor: Update playlist service and endpoints for global current playlist management

This commit is contained in:
JSC
2025-08-01 16:58:25 +02:00
parent 3132175354
commit c0f51b2e23
4 changed files with 63 additions and 30 deletions

View File

@@ -62,11 +62,11 @@ async def get_main_playlist(
@router.get("/current")
async def get_current_playlist(
current_user: Annotated[User, Depends(get_current_active_user_flexible)],
current_user: Annotated[User, Depends(get_current_active_user_flexible)], # noqa: ARG001
playlist_service: Annotated[PlaylistService, Depends(get_playlist_service)],
) -> PlaylistResponse:
"""Get the user's current playlist (falls back to main playlist)."""
playlist = await playlist_service.get_current_playlist(current_user.id)
"""Get the global current playlist (falls back to main playlist)."""
playlist = await playlist_service.get_current_playlist()
return PlaylistResponse.from_playlist(playlist)
@@ -105,13 +105,19 @@ async def update_playlist(
playlist_service: Annotated[PlaylistService, Depends(get_playlist_service)],
) -> PlaylistResponse:
"""Update a playlist."""
if current_user.id is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="User ID not available",
)
playlist = await playlist_service.update_playlist(
playlist_id=playlist_id,
user_id=current_user.id,
name=request.name,
description=request.description,
genre=request.genre,
is_current=request.is_current,
is_current=None, # is_current is not handled by this endpoint
)
return PlaylistResponse.from_playlist(playlist)
@@ -212,21 +218,21 @@ async def reorder_playlist_sounds(
@router.put("/{playlist_id}/set-current")
async def set_current_playlist(
playlist_id: int,
current_user: Annotated[User, Depends(get_current_active_user_flexible)],
current_user: Annotated[User, Depends(get_current_active_user_flexible)], # noqa: ARG001
playlist_service: Annotated[PlaylistService, Depends(get_playlist_service)],
) -> PlaylistResponse:
"""Set a playlist as the current playlist."""
playlist = await playlist_service.set_current_playlist(playlist_id, current_user.id)
"""Set a playlist as the global current playlist."""
playlist = await playlist_service.set_current_playlist_global(playlist_id)
return PlaylistResponse.from_playlist(playlist)
@router.delete("/current")
async def unset_current_playlist(
current_user: Annotated[User, Depends(get_current_active_user_flexible)],
current_user: Annotated[User, Depends(get_current_active_user_flexible)], # noqa: ARG001
playlist_service: Annotated[PlaylistService, Depends(get_playlist_service)],
) -> MessageResponse:
"""Unset the current playlist."""
await playlist_service.unset_current_playlist(current_user.id)
"""Unset the global current playlist."""
await playlist_service.unset_current_playlist_global()
return MessageResponse(message="Current playlist unset successfully")

View File

@@ -66,6 +66,18 @@ class PlaylistRepository(BaseRepository[Playlist]):
logger.exception("Failed to get current playlist for user: %s", user_id)
raise
async def get_global_current_playlist(self) -> Playlist | None:
"""Get the global current playlist (app-wide)."""
try:
statement = select(Playlist).where(
Playlist.is_current == True, # noqa: E712
)
result = await self.session.exec(statement)
return result.first()
except Exception:
logger.exception("Failed to get global current playlist")
raise
async def search_by_name(
self, query: str, user_id: int | None = None,
) -> list[Playlist]:

View File

@@ -54,9 +54,9 @@ class PlaylistService:
return main_playlist
async def get_current_playlist(self, user_id: int) -> Playlist:
"""Get the user's current playlist, fallback to main playlist."""
current_playlist = await self.playlist_repo.get_current_playlist(user_id)
async def get_current_playlist(self) -> Playlist:
"""Get the global current playlist, fallback to main playlist."""
current_playlist = await self.playlist_repo.get_global_current_playlist()
if current_playlist:
return current_playlist
@@ -317,6 +317,30 @@ class PlaylistService:
user_id,
)
# Global current playlist methods
async def set_current_playlist_global(self, playlist_id: int) -> Playlist:
"""Set a playlist as the global current playlist (app-wide)."""
playlist = await self.get_playlist_by_id(playlist_id)
# Unset any existing current playlist globally
await self._unset_global_current_playlist()
# Set new current playlist
playlist = await self.playlist_repo.update(playlist, {"is_current": True})
logger.info("Set playlist %s as global current playlist", playlist_id)
return playlist
async def unset_current_playlist_global(self) -> None:
"""Unset the global current playlist (main playlist becomes fallback)."""
await self._unset_global_current_playlist()
logger.info("Unset global current playlist, main playlist is now fallback")
async def _unset_global_current_playlist(self) -> None:
"""Unset any current playlist globally."""
current_playlist = await self.playlist_repo.get_global_current_playlist()
if current_playlist:
await self.playlist_repo.update(current_playlist, {"is_current": False})
async def _unset_current_playlist(self, user_id: int) -> None:
"""Unset the current playlist for a user."""
current_playlist = await self.playlist_repo.get_current_playlist(user_id)

View File

@@ -358,14 +358,14 @@ class TestPlaylistEndpoints:
assert data["genre"] == "jazz"
@pytest.mark.asyncio
async def test_update_playlist_set_current(
async def test_update_playlist_basic_fields(
self,
authenticated_client: AsyncClient,
test_session: AsyncSession,
test_user: User,
) -> None:
"""Test PUT /api/v1/playlists/{id} - set playlist as current."""
# Create test playlists within this test
"""Test PUT /api/v1/playlists/{id} - update basic fields only."""
# Create test playlist
user_id = test_user.id
test_playlist = Playlist(
user_id=user_id,
@@ -377,25 +377,13 @@ class TestPlaylistEndpoints:
is_deletable=True,
)
test_session.add(test_playlist)
# Note: main_playlist doesn't need to be current=True for this test
# The service logic handles current playlist management
main_playlist = Playlist(
user_id=None,
name="Main Playlist",
description="Main playlist",
is_main=True,
is_current=False,
is_deletable=False,
)
test_session.add(main_playlist)
await test_session.commit()
await test_session.refresh(test_playlist)
# Extract ID before HTTP request
playlist_id = test_playlist.id
payload = {"is_current": True}
payload = {"name": "Updated Playlist", "description": "Updated description"}
response = await authenticated_client.put(
f"/api/v1/playlists/{playlist_id}", json=payload,
@@ -403,7 +391,10 @@ class TestPlaylistEndpoints:
assert response.status_code == 200
data = response.json()
assert data["is_current"] is True
assert data["name"] == "Updated Playlist"
assert data["description"] == "Updated description"
# is_current should remain unchanged (not handled by this endpoint)
assert data["is_current"] is False
@pytest.mark.asyncio
async def test_delete_playlist_success(