geo/backend/app/api/brands.py

132 lines
3.8 KiB
Python

"""Brands API endpoints."""
import uuid
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession
from app.api.deps import get_current_user
from app.api.competitors import router as competitors_router
from app.api.scoring import router as scoring_router
from app.database import get_db
from app.models.user import User
from app.models.brand import Brand
from app.schemas.brand import BrandCreate, BrandUpdate, BrandResponse, BrandListResponse
router = APIRouter()
# Include competitors router under brands
router.include_router(competitors_router)
# Include scoring router under brands (/{brand_id}/score/, /{brand_id}/score/history/)
router.include_router(scoring_router)
@router.get("/", response_model=BrandListResponse)
async def get_brands(
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""Get all brands for the current user."""
stmt = select(Brand, func.count().over().label("total")).where(
Brand.user_id == current_user.id
)
result = await db.execute(stmt)
rows = result.all()
items = [row[0] for row in rows]
total = len(items)
return {"items": items, "total": total}
@router.post("/", response_model=BrandResponse, status_code=status.HTTP_201_CREATED)
async def create_brand(
brand_data: BrandCreate,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""Create a new brand."""
brand = Brand(
user_id=current_user.id,
name=brand_data.name,
aliases=brand_data.aliases,
website=brand_data.website,
industry=brand_data.industry,
platforms=brand_data.platforms,
frequency=brand_data.frequency,
)
db.add(brand)
await db.commit()
await db.refresh(brand)
return brand
@router.get("/{brand_id}/", response_model=BrandResponse)
async def get_brand(
brand_id: uuid.UUID,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""Get a specific brand by ID."""
stmt = select(Brand).where(Brand.id == brand_id, Brand.user_id == current_user.id)
result = await db.execute(stmt)
brand = result.scalar_one_or_none()
if not brand:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="品牌不存在",
)
return brand
@router.put("/{brand_id}/", response_model=BrandResponse)
async def update_brand(
brand_id: uuid.UUID,
brand_data: BrandUpdate,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""Update a brand."""
stmt = select(Brand).where(Brand.id == brand_id, Brand.user_id == current_user.id)
result = await db.execute(stmt)
brand = result.scalar_one_or_none()
if not brand:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="品牌不存在",
)
# Update only provided fields
update_data = brand_data.model_dump(exclude_unset=True)
for field, value in update_data.items():
setattr(brand, field, value)
await db.commit()
await db.refresh(brand)
return brand
@router.delete("/{brand_id}/", status_code=status.HTTP_204_NO_CONTENT)
async def delete_brand(
brand_id: uuid.UUID,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""Delete a brand."""
stmt = select(Brand).where(Brand.id == brand_id, Brand.user_id == current_user.id)
result = await db.execute(stmt)
brand = result.scalar_one_or_none()
if not brand:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="品牌不存在",
)
await db.delete(brand)
await db.commit()
return None