feat: 留言板 API + 零信任安全:后端 Token 鉴权强制覆写 operator_id

- 新增 GET/POST /products/{id}/messages 端点
- POST 创建留言时注入 current_user = Depends(get_current_user)
- operator_id 优先取 Token 中的 username,防止前端越权伪造发言身份
- 同时将 product.current_location_id 显示改为 formatUserName 映射
This commit is contained in:
2026-08-10 17:37:10 +08:00
parent b14773f81b
commit 1fe9c3d59d

View File

@ -3,9 +3,11 @@ from __future__ import annotations
from fastapi import APIRouter, Depends, Query from fastapi import APIRouter, Depends, Query
from fastapi.responses import Response from fastapi.responses import Response
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_db from app.core.database import get_db
from app.models.message import ProductMessage
from app.schemas.product import ( from app.schemas.product import (
ProductCreate, ProductCreate,
ProductUpdate, ProductUpdate,
@ -136,3 +138,51 @@ async def update_product_overall_status(
合法值: 备货 | 生产 | 测试 | 维修 | 在库 合法值: 备货 | 生产 | 测试 | 维修 | 在库
""" """
return await product_service.update_overall_status(db, serial_number, data.status) return await product_service.update_overall_status(db, serial_number, data.status)
# ============================================================
# 协同留言板
# ============================================================
class MessageCreate(BaseModel):
operator_id: str = Field(..., min_length=1, max_length=50, description="留言人姓名或工号")
content: str = Field(..., min_length=1, description="留言内容")
@router.get("/{product_id}/messages")
async def get_product_messages(
product_id: str,
db: AsyncSession = Depends(get_db),
):
"""获取某产品的所有留言(按时间正序)"""
result = await db.execute(
select(ProductMessage)
.where(ProductMessage.product_id == product_id)
.order_by(ProductMessage.created_at.asc())
)
return result.scalars().all()
@router.post("/{product_id}/messages", status_code=201)
async def create_product_message(
product_id: str,
request: MessageCreate,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""发布新留言operator_id 由后端 Token 强制覆写,防止越权伪造)"""
import uuid
real_operator_id = (
current_user.get("username")
or current_user.get("sub")
or request.operator_id
)
msg = ProductMessage(
product_id=uuid.UUID(product_id),
operator_id=real_operator_id,
content=request.content,
)
db.add(msg)
await db.commit()
await db.refresh(msg)
return msg