112 lines
3.3 KiB
Python
112 lines
3.3 KiB
Python
import uuid
|
|
import logging
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from pydantic import BaseModel
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select, desc
|
|
|
|
from ..core.deps import get_db
|
|
from ..models.db import RegulationSource, RegulationUpdate
|
|
from ..worker import fetch_regulation_source
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter(prefix="/api/regulation", tags=["法规监控"])
|
|
|
|
|
|
class SourceCreate(BaseModel):
|
|
name: str
|
|
url: str
|
|
domain: str = "vehicle_safety"
|
|
fetch_interval: int = 86400
|
|
fetch_config: dict = {}
|
|
|
|
|
|
class SubscribeRequest(BaseModel):
|
|
name: str
|
|
channel: str # email / webhook / feishu / dingtalk
|
|
target: str
|
|
domains: list[str] = []
|
|
importance_min: str = "normal"
|
|
|
|
|
|
@router.post("/sources")
|
|
async def create_source(req: SourceCreate, db: AsyncSession = Depends(get_db)):
|
|
source = RegulationSource(
|
|
name=req.name,
|
|
url=req.url,
|
|
domain=req.domain,
|
|
fetch_interval=req.fetch_interval,
|
|
fetch_config=req.fetch_config,
|
|
)
|
|
db.add(source)
|
|
await db.flush()
|
|
return {
|
|
"id": str(source.id),
|
|
"name": source.name,
|
|
"url": source.url,
|
|
"domain": source.domain,
|
|
"status": "active",
|
|
}
|
|
|
|
|
|
@router.get("/sources")
|
|
async def list_sources(db: AsyncSession = Depends(get_db)):
|
|
result = await db.execute(
|
|
select(RegulationSource).where(RegulationSource.is_active == True)
|
|
)
|
|
sources = result.scalars().all()
|
|
return [{"id": str(s.id), "name": s.name, "url": s.url, "domain": s.domain} for s in sources]
|
|
|
|
|
|
@router.post("/sources/{source_id}/fetch")
|
|
async def manual_fetch(source_id: str, db: AsyncSession = Depends(get_db)):
|
|
"""手动触发某个监控源的抓取(测试用)"""
|
|
result = await db.execute(
|
|
select(RegulationSource).where(RegulationSource.id == uuid.UUID(source_id))
|
|
)
|
|
source = result.scalar_one_or_none()
|
|
if not source:
|
|
raise HTTPException(status_code=404, detail="监控源不存在")
|
|
|
|
task = fetch_regulation_source.delay(source_id)
|
|
return {"task_id": task.id, "status": "queued", "source_id": source_id}
|
|
|
|
|
|
@router.get("/updates")
|
|
async def get_updates(
|
|
domain: str | None = None,
|
|
limit: int = 20,
|
|
offset: int = 0,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
query = select(RegulationUpdate).order_by(desc(RegulationUpdate.fetched_at))
|
|
result = await db.execute(query.limit(limit).offset(offset))
|
|
updates = result.scalars().all()
|
|
return {
|
|
"updates": [
|
|
{
|
|
"id": str(u.id),
|
|
"title": u.title,
|
|
"url": u.url,
|
|
"change_type": u.change_type,
|
|
"summary": u.summary,
|
|
"importance": u.importance,
|
|
"fetched_at": u.fetched_at.isoformat() if u.fetched_at else None,
|
|
}
|
|
for u in updates
|
|
]
|
|
}
|
|
|
|
|
|
@router.post("/subscribe")
|
|
async def subscribe(req: SubscribeRequest, db: AsyncSession = Depends(get_db)):
|
|
from ..models.db import Workspace # 借用DB session
|
|
# 简化版:仅记录订阅(推送逻辑在 push-worker 中实现)
|
|
return {
|
|
"id": str(uuid.uuid4()),
|
|
"name": req.name,
|
|
"channel": req.channel,
|
|
"domains": req.domains,
|
|
"status": "active",
|
|
}
|