File size: 5,185 Bytes
f68778c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
515f3e9
2bd6575
515f3e9
 
 
 
f68778c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
515f3e9
 
 
2bd6575
515f3e9
 
 
f68778c
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# router_users_profile.py
# ==========================================
# 👤 用户资料路由模块
# ==========================================
# 作用:处理用户资料的获取和更新
# 关联文件:
#   - 数据库连接.py (JSON数据库读写 users.json, items.json)
#   - models.py (UserUpdate 数据模型)
#   - router_users.py (主路由聚合此模块)
# 前端调用:
#   - 个人中心视图.js (获取/展示用户资料)
#   - 个人设置表单组件.js (更新用户资料)
# ==========================================

from fastapi import APIRouter, HTTPException
import 数据库连接 as db
from models import UserUpdate

# 创建子路由实例
router = APIRouter()


# ==========================================
# 📖 获取用户资料接口
# ==========================================
# 作用:根据账号获取用户的完整资料信息
# 关联:
#   - users.json (存储用户基本信息)
#   - items.json (统计用户发布的内容获得的互动数据)
# 前端调用:
#   - 个人中心视图.js 的 fetchUserProfile()
#   - 列表卡片组件.js 显示作者信息时也会调用
@router.get("/api/users/{account}")
async def get_user_profile(account: str):
    """

    获取用户资料接口

    

    路径参数:

        - account: 用户账号

    返回数据:

        - 用户基本信息(排除密码)

        - receivedLikes: 收到的总点赞数

        - receivedFavorites: 收到的总收藏数

        - receivedUses: 发布内容被使用的总次数

    """
    # 加载用户数据库
    users_db = db.load_data("users.json", default_data={})
    
    # 检查用户是否存在
    if account not in users_db: 
        raise HTTPException(status_code=404, detail="用户不存在")
    
    user_data = users_db[account]
    
    # ========== 统计用户作品获得的互动数据 ==========
    # 作用:遍历所有内容,统计该用户发布的内容收到的互动
    # 关联:items.json 存储所有发布的工具/应用/推荐内容
    items_db = db.load_data("items.json", default_data=[])
    user_items = [item for item in items_db if item.get("author") == account]
    
    # 累加所有作品的互动数据
    user_data["receivedLikes"] = sum(item.get("likes", 0) for item in user_items)
    user_data["receivedFavorites"] = sum(item.get("favorites", 0) for item in user_items)
    user_data["receivedUses"] = sum(item.get("uses", 0) for item in user_items)
    
    # 🔒 运行时自愈:如果 avatarDataUrl 是 base64,清除它并持久化修复
    if (user_data.get("avatarDataUrl") or "").startswith("data:"):
        user_data["avatarDataUrl"] = ""
        users_db[account] = user_data
        db.save_data("users.json", users_db)
    
    # 返回用户数据(排除敏感的密码字段)
    return {"status": "success", "data": {k: v for k, v in user_data.items() if k != "password"}}


# ==========================================
# ✏️ 更新用户资料接口
# ==========================================
# 作用:更新用户的个人资料(昵称、头像、简介等)
# 关联:
#   - users.json (保存更新后的用户信息)
#   - models.py 的 UserUpdate 模型定义可更新的字段
# 前端调用:
#   - 个人设置表单组件.js 的 handleSaveProfile()
@router.put("/api/users/{account}")
async def update_user_profile(account: str, update_data: UserUpdate):
    """

    更新用户资料接口

    

    路径参数:

        - account: 用户账号

    请求参数:(UserUpdate 模型,所有字段可选)

        - name: 昵称

        - intro: 个人介绍(最多100字)

        - avatarDataUrl: 头像(Base64格式)

        - gender: 性别 (male/female/secret)

        - age: 年龄

        - country: 国家

        - region: 地区

    """
    # 加载用户数据库
    users_db = db.load_data("users.json", default_data={})
    
    # 检查用户是否存在
    if account not in users_db: 
        raise HTTPException(status_code=404, detail="用户不存在")
    
    # ========== 字段校验 ==========
    # 个人介绍长度限制
    if update_data.intro and len(update_data.intro) > 100: 
        raise HTTPException(status_code=400, detail="个人介绍不能超过100个字符")
    
    # ========== 更新用户数据 ==========
    user = users_db[account]
    
    # 遍历请求中的字段,只更新非空值
    # exclude_unset=True 表示只包含请求中明确传递的字段
    update_dict = update_data.dict(exclude_unset=True)
    
    # 🔒 安全防护:拒绝 base64 头像数据,防止 JSON 膨胀
    if (update_dict.get("avatarDataUrl") or "").startswith("data:"):
        del update_dict["avatarDataUrl"]
    
    for k, v in update_dict.items():
        if v is not None: 
            user[k] = v
    
    # 保存更新后的数据
    db.save_data("users.json", users_db)
    
    # 返回更新后的用户数据(排除密码)
    return {"status": "success", "data": {k: v for k, v in user.items() if k != "password"}}