feat(init): 添加完整的认证和业务路由模块
- 实现微信登录、手机号绑定、token验证和登出功能 - 添加打卡系统,支持正常、迟到、请假等状态记录 - 集成课程投票功能,支持多课程选择和评分评论 - 开发反馈系统,支持图文反馈提交和管理员处理 - 构建首页页面模块,动态展示学习资源和个人信息 - 设计计划管理系统,支持周/月/年计划制定和跟踪 - 实现小组计划统计和历史记录查询功能 - 完善用户认证会话管理和数据库交互逻辑
This commit is contained in:
83
routes/profile.py
Normal file
83
routes/profile.py
Normal file
@@ -0,0 +1,83 @@
|
||||
import os
|
||||
|
||||
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile
|
||||
from pydantic import BaseModel
|
||||
|
||||
from .. import config, db
|
||||
from ..user import user_payload
|
||||
from .auth import get_current_user
|
||||
|
||||
router = APIRouter(prefix="/api/v1/profile", tags=["profile"])
|
||||
|
||||
MAX_AVATAR_SIZE = 4 * 1024 * 1024
|
||||
ALLOWED_AVATAR_EXT = {".png", ".jpg", ".jpeg", ".webp"}
|
||||
|
||||
|
||||
def _profile(user):
|
||||
payload = user_payload(user)
|
||||
return {
|
||||
"name": payload["name"],
|
||||
"student_id": payload["student_id"],
|
||||
"display_name": payload["display_name"],
|
||||
"wechat_nickname": user.get("wechat_nickname", ""),
|
||||
"phone": user.get("phone_display", "") or "",
|
||||
"group": payload["group"],
|
||||
"role": payload["role"],
|
||||
"class_groups": payload["class_groups"],
|
||||
"wechat_avatar": user.get("wechat_avatar", ""),
|
||||
"login_type": user.get("login_type", ""),
|
||||
}
|
||||
|
||||
|
||||
class ProfileUpdateRequest(BaseModel):
|
||||
wechat_nickname: str = ""
|
||||
wechat_avatar: str = ""
|
||||
|
||||
|
||||
@router.get("")
|
||||
def get_profile(user=Depends(get_current_user)):
|
||||
return {"success": True, **_profile(user)}
|
||||
|
||||
|
||||
@router.put("")
|
||||
def update_profile(req: ProfileUpdateRequest, user=Depends(get_current_user)):
|
||||
db.execute(
|
||||
"UPDATE auth_users SET wechat_nickname=%s, wechat_avatar=%s WHERE id=%s",
|
||||
(req.wechat_nickname, req.wechat_avatar, user["id"]),
|
||||
)
|
||||
fresh = db.fetch_one("SELECT * FROM auth_users WHERE id=%s", (user["id"],))
|
||||
return {"success": True, **_profile(fresh or user)}
|
||||
|
||||
|
||||
@router.post("/avatar")
|
||||
def upload_avatar(file: UploadFile = File(...), user=Depends(get_current_user)):
|
||||
data = file.file.read()
|
||||
if len(data) > MAX_AVATAR_SIZE:
|
||||
raise HTTPException(status_code=400, detail="头像不能超过4MB")
|
||||
|
||||
safe_name = os.path.basename(file.filename or "")
|
||||
ext = os.path.splitext(safe_name)[1].lower()
|
||||
if ext not in ALLOWED_AVATAR_EXT:
|
||||
raise HTTPException(status_code=400, detail="不支持的文件类型")
|
||||
|
||||
avatar_base = config.AVATAR_DIR
|
||||
uid = str(user["id"])
|
||||
save_dir = os.path.join(avatar_base, uid)
|
||||
os.makedirs(save_dir, exist_ok=True)
|
||||
for old_name in os.listdir(save_dir):
|
||||
if old_name.startswith("avatar.") and old_name != "avatar" + ext:
|
||||
try:
|
||||
os.remove(os.path.join(save_dir, old_name))
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
filename = "avatar" + ext
|
||||
file_path = os.path.join(save_dir, filename)
|
||||
with open(file_path, "wb") as f:
|
||||
f.write(data)
|
||||
|
||||
url_path = "/clock/static/avatars/" + uid + "/" + filename
|
||||
|
||||
db.execute("UPDATE auth_users SET wechat_avatar=%s WHERE id=%s", (url_path, user["id"]))
|
||||
return {"success": True, "wechat_avatar": url_path}
|
||||
|
||||
Reference in New Issue
Block a user