from fastapi import APIRouter, HTTPException, Depends from pydantic import BaseModel from typing import Optional import auth import issue_db router = APIRouter() class IssueCreate(BaseModel): title: str type: str = "bug" description: str markdown_sample: str = "" class ReplyCreate(BaseModel): content: str class StatusUpdate(BaseModel): status: str # ==================== 用户接口 ==================== @router.post("/api/issues") def create_issue(data: IssueCreate, current_user: dict = Depends(auth.get_current_user)): """用户提交新 Issue""" if not data.title or not data.title.strip(): raise HTTPException(status_code=400, detail="标题不能为空") if not data.description or not data.description.strip(): raise HTTPException(status_code=400, detail="描述不能为空") if data.type not in ("bug", "feature", "other"): raise HTTPException(status_code=400, detail="类型无效,请选择 bug / feature / other") new_issue = issue_db.create_issue( user_id=current_user["id"], username=current_user["username"], title=data.title.strip(), issue_type=data.type, description=data.description.strip(), markdown_sample=data.markdown_sample ) return {"message": "Issue 已提交", "issue": new_issue} @router.get("/api/issues/my") def get_my_issues(current_user: dict = Depends(auth.get_current_user)): """获取当前用户提交的 Issue 列表""" issues = issue_db.get_user_issues(current_user["id"]) return {"issues": issues} @router.get("/api/issues/{issue_id}") def get_issue_detail(issue_id: int, current_user: dict = Depends(auth.get_current_user)): """获取单条 Issue 详情(用户只能查看自己的,admin 可以查看所有)""" issue = issue_db.get_issue_by_id(issue_id) if not issue: raise HTTPException(status_code=404, detail="Issue 不存在") # 权限校验:只有 Issue 提交者或 admin 可以查看 if issue["user_id"] != current_user["id"] and current_user["username"] != "admin": raise HTTPException(status_code=403, detail="无权查看此 Issue") return {"issue": issue} @router.post("/api/issues/{issue_id}/reply") def user_reply_issue(issue_id: int, data: ReplyCreate, current_user: dict = Depends(auth.get_current_user)): """用户对自己的 Issue 追加回复""" if not data.content or not data.content.strip(): raise HTTPException(status_code=400, detail="回复内容不能为空") issue = issue_db.get_issue_by_id(issue_id) if not issue: raise HTTPException(status_code=404, detail="Issue 不存在") if issue["user_id"] != current_user["id"] and current_user["username"] != "admin": raise HTTPException(status_code=403, detail="无权回复此 Issue") reply = issue_db.add_reply(issue_id, current_user["username"], data.content.strip()) if not reply: raise HTTPException(status_code=500, detail="回复失败") return {"message": "回复成功", "reply": reply} # ==================== 管理员接口 ==================== @router.get("/api/admin/issues") def admin_get_all_issues(current_user: dict = Depends(auth.get_current_user)): """管理员获取所有 Issue""" if current_user["username"] != "admin": raise HTTPException(status_code=403, detail="无权访问,需要管理员权限") issues = issue_db.get_all_issues() return {"issues": issues, "total": len(issues)} @router.post("/api/admin/issues/{issue_id}/reply") def admin_reply_issue(issue_id: int, data: ReplyCreate, current_user: dict = Depends(auth.get_current_user)): """管理员回复 Issue""" if current_user["username"] != "admin": raise HTTPException(status_code=403, detail="无权访问") if not data.content or not data.content.strip(): raise HTTPException(status_code=400, detail="回复内容不能为空") issue = issue_db.get_issue_by_id(issue_id) if not issue: raise HTTPException(status_code=404, detail="Issue 不存在") reply = issue_db.add_reply(issue_id, "admin", data.content.strip()) if not reply: raise HTTPException(status_code=500, detail="回复失败") return {"message": "回复成功", "reply": reply} @router.put("/api/admin/issues/{issue_id}/status") def admin_update_status(issue_id: int, data: StatusUpdate, current_user: dict = Depends(auth.get_current_user)): """管理员更新 Issue 状态""" if current_user["username"] != "admin": raise HTTPException(status_code=403, detail="无权访问") if data.status not in ("open", "in_progress", "closed"): raise HTTPException(status_code=400, detail="状态无效,请选择 open / in_progress / closed") issue = issue_db.update_issue_status(issue_id, data.status) if not issue: raise HTTPException(status_code=404, detail="Issue 不存在") return {"message": "状态更新成功", "issue": issue}