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:
@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user