"""Admin CRUD for parse channels (Telegram handles in MVP).""" from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from ..database import get_db from ..models import ParseChannel, ParseJob from ..schemas import ParseChannelCreate, ParseChannelRead, ParseChannelUpdate router = APIRouter(prefix="/admin/parse-channels", tags=["parse-channels"]) ALLOWED_SOURCE_TYPES = {"telegram"} @router.get("", response_model=list[ParseChannelRead]) def list_channels(db: Session = Depends(get_db)): return db.query(ParseChannel).order_by(ParseChannel.id.desc()).all() @router.post("", response_model=ParseChannelRead, status_code=201) def create_channel(payload: ParseChannelCreate, db: Session = Depends(get_db)): source_type = (payload.source_type or "telegram").strip() if source_type not in ALLOWED_SOURCE_TYPES: raise HTTPException( status_code=400, detail=f"source_type must be one of: {', '.join(sorted(ALLOWED_SOURCE_TYPES))}", ) channel = ParseChannel( name=payload.name.strip(), source_type=source_type, channel=payload.channel.strip().lstrip("@"), is_active=payload.is_active, ) db.add(channel) db.commit() db.refresh(channel) return channel @router.get("/{channel_id}", response_model=ParseChannelRead) def get_channel(channel_id: int, db: Session = Depends(get_db)): channel = db.query(ParseChannel).filter(ParseChannel.id == channel_id).first() if not channel: raise HTTPException(status_code=404, detail="Channel not found") return channel @router.patch("/{channel_id}", response_model=ParseChannelRead) def update_channel( channel_id: int, payload: ParseChannelUpdate, db: Session = Depends(get_db), ): channel = db.query(ParseChannel).filter(ParseChannel.id == channel_id).first() if not channel: raise HTTPException(status_code=404, detail="Channel not found") if payload.name is not None: channel.name = payload.name.strip() if payload.source_type is not None: source_type = payload.source_type.strip() if source_type not in ALLOWED_SOURCE_TYPES: raise HTTPException( status_code=400, detail=f"source_type must be one of: {', '.join(sorted(ALLOWED_SOURCE_TYPES))}", ) channel.source_type = source_type if payload.channel is not None: channel.channel = payload.channel.strip().lstrip("@") if payload.is_active is not None: channel.is_active = payload.is_active db.commit() db.refresh(channel) return channel @router.delete("/{channel_id}", status_code=204) def delete_channel(channel_id: int, db: Session = Depends(get_db)): channel = db.query(ParseChannel).filter(ParseChannel.id == channel_id).first() if not channel: raise HTTPException(status_code=404, detail="Channel not found") linked = ( db.query(ParseJob) .filter(ParseJob.channel_id == channel_id, ParseJob.status.in_(("queued", "running"))) .count() ) if linked: raise HTTPException( status_code=409, detail="Cannot delete channel used by queued/running jobs", ) db.delete(channel) db.commit()