import uuid from datetime import datetime from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from ..dependencies import get_db, get_current_user, require_admin from ..models.user import User from ..models.session import PlaybackSession from ..services.auth import hash_password from ..schemas.user import UserCreate, UserUpdate, UserOut, UserSettings from ..routers.auth import _build_user_out router = APIRouter(prefix="/api/users", tags=["users"]) @router.get("") async def list_users( admin: User = Depends(require_admin), db: AsyncSession = Depends(get_db), ): result = await db.execute(select(User)) users = result.scalars().all() return [_build_user_out(u).model_dump(by_alias=True) for u in users] @router.post("") async def create_user( body: UserCreate, admin: User = Depends(require_admin), db: AsyncSession = Depends(get_db), ): existing = await db.execute(select(User).where(User.username == body.username)) if existing.scalar_one_or_none(): raise HTTPException(status_code=400, detail="Username already exists") user = User( id=str(uuid.uuid4()), username=body.username, email=body.email, password_hash=hash_password(body.password), is_admin=body.is_admin, ) db.add(user) await db.commit() await db.refresh(user) return _build_user_out(user).model_dump(by_alias=True) @router.get("/{user_id}") async def get_user( user_id: str, admin: User = Depends(require_admin), db: AsyncSession = Depends(get_db), ): result = await db.execute(select(User).where(User.id == user_id)) user = result.scalar_one_or_none() if not user: raise HTTPException(status_code=404, detail="User not found") return _build_user_out(user).model_dump(by_alias=True) @router.patch("/{user_id}") async def update_user( user_id: str, body: UserUpdate, admin: User = Depends(require_admin), db: AsyncSession = Depends(get_db), ): result = await db.execute(select(User).where(User.id == user_id)) user = result.scalar_one_or_none() if not user: raise HTTPException(status_code=404, detail="User not found") if body.email is not None: user.email = body.email if body.password is not None: user.password_hash = hash_password(body.password) if body.is_admin is not None: user.is_admin = body.is_admin if body.is_active is not None: user.is_active = body.is_active if body.settings is not None: user.settings = {**(user.settings or {}), **body.settings} user.updated_at = datetime.utcnow() await db.commit() await db.refresh(user) return _build_user_out(user).model_dump(by_alias=True) @router.delete("/{user_id}") async def delete_user( user_id: str, admin: User = Depends(require_admin), db: AsyncSession = Depends(get_db), ): result = await db.execute(select(User).where(User.id == user_id)) user = result.scalar_one_or_none() if not user: raise HTTPException(status_code=404, detail="User not found") if user.is_admin: # Sicherstellen dass mindestens ein Admin übrig bleibt admin_count_result = await db.execute( select(User).where(User.is_admin == True) ) admins = admin_count_result.scalars().all() if len(admins) <= 1: raise HTTPException(status_code=400, detail="Cannot delete the last admin") await db.delete(user) await db.commit() return {"success": True} @router.get("/{user_id}/listening-sessions") async def get_listening_sessions( user_id: str, admin: User = Depends(require_admin), db: AsyncSession = Depends(get_db), ): result = await db.execute( select(PlaybackSession) .where(PlaybackSession.user_id == user_id) .order_by(PlaybackSession.updated_at.desc()) .limit(100) ) sessions = result.scalars().all() return { "sessions": [ { "id": s.id, "userId": s.user_id, "libraryItemId": s.library_item_id, "episodeId": s.episode_id, "mediaType": s.media_type, "currentTime": s.current_time, "duration": s.duration, "startedAt": int(s.started_at.timestamp() * 1000) if s.started_at else 0, "updatedAt": int(s.updated_at.timestamp() * 1000) if s.updated_at else 0, } for s in sessions ] } @router.get("/{user_id}/listening-stats") async def get_listening_stats( user_id: str, admin: User = Depends(require_admin), db: AsyncSession = Depends(get_db), ): result = await db.execute( select(PlaybackSession).where(PlaybackSession.user_id == user_id) ) sessions = result.scalars().all() total_time = sum(s.duration for s in sessions if s.duration) return { "totalTime": total_time, "numSessions": len(sessions), "days": {}, }