127 lines
3.7 KiB
Python

from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from proxy_pool.common.dependencies import get_db, get_registry
from proxy_pool.plugins.registry import PluginRegistry
from proxy_pool.proxy.models import ProxySource
from proxy_pool.proxy.schemas import (
ProxySourceCreate,
ProxySourceResponse,
ProxySourceUpdate,
)
router = APIRouter(prefix="/sources", tags=["sources"])
@router.get("", response_model=list[ProxySourceResponse])
async def list_sources(
is_active: bool | None = None,
db: AsyncSession = Depends(get_db),
) -> list[ProxySourceResponse]:
query = select(ProxySource)
if is_active is not None:
query = query.where(ProxySource.is_active == is_active)
query = query.order_by(ProxySource.created_at.desc())
result = await db.execute(query)
sources = result.scalars().all()
return [ProxySourceResponse.model_validate(s) for s in sources]
@router.post(
"",
response_model=ProxySourceResponse,
status_code=status.HTTP_201_CREATED,
)
async def create_source(
body: ProxySourceCreate,
db: AsyncSession = Depends(get_db),
registry: PluginRegistry = Depends(get_registry),
) -> ProxySourceResponse:
# Validate parser exists
try:
registry.get_parser(body.parser_name)
except Exception:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
detail=f"No parser registered with name '{body.parser_name}'",
) from None
source = ProxySource(
url=body.url,
parser_name=body.parser_name,
cron_schedule=body.cron_schedule,
default_protocol=body.default_protocol,
)
db.add(source)
await db.commit()
await db.refresh(source)
return ProxySourceResponse.model_validate(source)
@router.get("/{source_id}", response_model=ProxySourceResponse)
async def get_source(
source_id: UUID,
db: AsyncSession = Depends(get_db),
) -> ProxySourceResponse:
source = await db.get(ProxySource, source_id)
if source is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Source not found",
)
return ProxySourceResponse.model_validate(source)
@router.patch("/{source_id}", response_model=ProxySourceResponse)
async def update_source(
source_id: UUID,
body: ProxySourceUpdate,
db: AsyncSession = Depends(get_db),
registry: PluginRegistry = Depends(get_registry),
) -> ProxySourceResponse:
source = await db.get(ProxySource, source_id)
if source is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Source not found",
)
update_data = body.model_dump(exclude_unset=True)
if "parser_name" in update_data:
try:
registry.get_parser(update_data["parser_name"])
except Exception:
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
detail=f"No parser registered with name '{update_data['parser_name']}'",
) from None
for field, value in update_data.items():
setattr(source, field, value)
await db.commit()
await db.refresh(source)
return ProxySourceResponse.model_validate(source)
@router.delete("/{source_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_source(
source_id: UUID,
db: AsyncSession = Depends(get_db),
) -> None:
source = await db.get(ProxySource, source_id)
if source is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Source not found",
)
await db.delete(source)
await db.commit()