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.responses import Response
from pydantic import BaseModel, Field
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_db
from app.models.message import ProductMessage
from app.schemas.product import (
ProductCreate,
ProductUpdate,
@ -136,3 +138,51 @@ async def update_product_overall_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