from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.orm import Session from typing import List from uuid import UUID from sqlalchemy import and_ from app.models import ( ChannelDB, ChannelURL, ChannelCreate, ChannelUpdate, ChannelResponse, ChannelURLCreate, ChannelURLResponse, ) from app.utils.database import get_db from app.auth.dependencies import get_current_user, require_roles from app.models.auth import CognitoUser router = APIRouter( prefix="/channels", tags=["channels"] ) @router.post("/", response_model=ChannelResponse, status_code=status.HTTP_201_CREATED) @require_roles("admin") def create_channel( channel: ChannelCreate, db: Session = Depends(get_db), user: CognitoUser = Depends(get_current_user) ): """Create a new channel""" # Check for duplicate channel (same group_title + name) existing_channel = db.query(ChannelDB).filter( and_( ChannelDB.group_title == channel.group_title, ChannelDB.name == channel.name ) ).first() if existing_channel: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Channel with same group_title and name already exists" ) # Create channel without URLs first channel_data = channel.model_dump() urls = channel_data.pop('urls', []) db_channel = ChannelDB(**channel_data) db.add(db_channel) db.commit() db.refresh(db_channel) # Add URLs for url in urls: db_url = ChannelURL(channel_id=db_channel.id, url=url) db.add(db_url) db.commit() db.refresh(db_channel) return db_channel @router.get("/{channel_id}", response_model=ChannelResponse) def get_channel( channel_id: UUID, db: Session = Depends(get_db) ): """Get a channel by id""" channel = db.query(ChannelDB).filter(ChannelDB.id == channel_id).first() if not channel: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Channel not found" ) return channel @router.put("/{channel_id}", response_model=ChannelResponse) @require_roles("admin") def update_channel( channel_id: UUID, channel: ChannelUpdate, db: Session = Depends(get_db), user: CognitoUser = Depends(get_current_user) ): """Update a channel""" db_channel = db.query(ChannelDB).filter(ChannelDB.id == channel_id).first() if not db_channel: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Channel not found" ) # Check for duplicate channel (same group_title + name) excluding current channel existing_channel = db.query(ChannelDB).filter( and_( ChannelDB.group_title == channel.group_title, ChannelDB.name == channel.name, ChannelDB.id != channel_id ) ).first() if existing_channel: raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail="Channel with same group_title and name already exists" ) for key, value in channel.model_dump().items(): setattr(db_channel, key, value) db.commit() db.refresh(db_channel) return db_channel @router.delete("/{channel_id}", status_code=status.HTTP_204_NO_CONTENT) @require_roles("admin") def delete_channel( channel_id: UUID, db: Session = Depends(get_db), user: CognitoUser = Depends(get_current_user) ): """Delete a channel""" channel = db.query(ChannelDB).filter(ChannelDB.id == channel_id).first() if not channel: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Channel not found" ) db.delete(channel) db.commit() return None @router.get("/", response_model=List[ChannelResponse]) @require_roles("admin") def list_channels( skip: int = 0, limit: int = 100, db: Session = Depends(get_db), user: CognitoUser = Depends(get_current_user) ): """List all channels with pagination""" return db.query(ChannelDB).offset(skip).limit(limit).all() # URL Management Endpoints @router.post("/{channel_id}/urls", response_model=ChannelURLResponse, status_code=status.HTTP_201_CREATED) @require_roles("admin") def add_channel_url( channel_id: UUID, url: ChannelURLCreate, db: Session = Depends(get_db), user: CognitoUser = Depends(get_current_user) ): """Add a new URL to a channel""" channel = db.query(ChannelDB).filter(ChannelDB.id == channel_id).first() if not channel: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Channel not found" ) db_url = ChannelURL(channel_id=channel_id, url=url.url) db.add(db_url) db.commit() db.refresh(db_url) return db_url @router.delete("/{channel_id}/urls/{url_id}", status_code=status.HTTP_204_NO_CONTENT) @require_roles("admin") def delete_channel_url( channel_id: UUID, url_id: UUID, db: Session = Depends(get_db), user: CognitoUser = Depends(get_current_user) ): """Delete a URL from a channel""" url = db.query(ChannelURL).filter( and_( ChannelURL.id == url_id, ChannelURL.channel_id == channel_id ) ).first() if not url: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="URL not found" ) db.delete(url) db.commit() return None @router.get("/{channel_id}/urls", response_model=List[ChannelURLResponse]) @require_roles("admin") def list_channel_urls( channel_id: UUID, db: Session = Depends(get_db), user: CognitoUser = Depends(get_current_user) ): """List all URLs for a channel""" channel = db.query(ChannelDB).filter(ChannelDB.id == channel_id).first() if not channel: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail="Channel not found" ) return db.query(ChannelURL).filter(ChannelURL.channel_id == channel_id).all()