goon/app/api/scene_favorites.py
goon-foss a4486980a4 style: myslniki em/en z komentarzy i docstringow (calosc repo)
1745 wystapien w 291 plikach (backend, scripts, mobile). Dominowal jeden ksztalt,
' — ' laczace zdania, wiec poszedl przecinek; myslnik otwierajacy mysl zdjety;
zakresy 0–5 i A–Z na dywiz.

Podzial komentarz/kod robil skaner stanow, nie regex, zeby nie ruszyc myslnika
stojacego w stringu albo w wyrazeniu regularnym. Potwierdzone maszynowo: po wycieciu
komentarzy z wersji HEAD i z dysku obie sa identyczne we wszystkich 291 plikach,
czyli poza komentarzami nie zmienilo sie nic. 233 pliki .py parsuja sie bez bledu,
tsc ma te same 11 bledow w tych samych 3 plikach co przed zmiana.

Dwie rzeczy wymagaly poprawki po automacie: wyrownane listy definicji, gdzie myslnik
byl separatorem kolumny (37 miejsc, kolumna przywrocona), i trzy przeniesienia mysli
do nowej linii, gdzie zostawal wiszacy przecinek na poczatku (poprawione recznie).

Bundla nie republikuje: Hermes i tak nie niesie komentarzy, wiec dla uzytkownika
to zero zmiany.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 11:51:57 +02:00

88 lines
2.7 KiB
Python

"""Scene favorites, ulubione sceny (single-user, równolegle do /favorites/performers).
Endpointy:
GET /scene-favorites lista ulubionych scen (pełen SceneOut)
POST /scene-favorites/{scene_id} dodaj (idempotent)
DELETE /scene-favorites/{scene_id} usuń
"""
from __future__ import annotations
import uuid
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.api.device import get_device_id
from app.api.scenes import _build_scene_out
from app.api.schemas import SceneOut
from app.auth import require_api_key
from app.db import get_session
from app.models.favorite_scene import FavoriteScene
from app.models.scene import Scene
router = APIRouter(
prefix="/scene-favorites",
tags=["scene-favorites"],
dependencies=[Depends(require_api_key)],
)
class SceneFavoriteListOut(BaseModel):
items: list[SceneOut]
total: int
class SceneFavoriteToggleOut(BaseModel):
scene_id: uuid.UUID
favorited: bool
@router.get("", response_model=SceneFavoriteListOut)
def list_scene_favorites(
session: Annotated[Session, Depends(get_session)],
device_id: Annotated[str, Depends(get_device_id)],
) -> SceneFavoriteListOut:
rows = (
session.execute(
select(Scene, FavoriteScene)
.join(FavoriteScene, FavoriteScene.scene_id == Scene.id)
.where(FavoriteScene.device_id == device_id)
.order_by(FavoriteScene.created_at.desc())
)
.all()
)
items = [_build_scene_out(session, scene, device_id=device_id) for scene, _ in rows]
return SceneFavoriteListOut(items=items, total=len(items))
@router.post(
"/{scene_id}",
response_model=SceneFavoriteToggleOut,
status_code=status.HTTP_201_CREATED,
)
def add_scene_favorite(
scene_id: uuid.UUID,
session: Annotated[Session, Depends(get_session)],
device_id: Annotated[str, Depends(get_device_id)],
) -> SceneFavoriteToggleOut:
scene = session.get(Scene, scene_id)
if scene is None:
raise HTTPException(status_code=404, detail="scene not found")
existing = session.get(FavoriteScene, (device_id, scene_id))
if existing is None:
session.add(FavoriteScene(device_id=device_id, scene_id=scene_id))
return SceneFavoriteToggleOut(scene_id=scene_id, favorited=True)
@router.delete("/{scene_id}", status_code=status.HTTP_204_NO_CONTENT)
def remove_scene_favorite(
scene_id: uuid.UUID,
session: Annotated[Session, Depends(get_session)],
device_id: Annotated[str, Depends(get_device_id)],
) -> None:
fav = session.get(FavoriteScene, (device_id, scene_id))
if fav is not None:
session.delete(fav)