ZHIWEI666 commited on
Commit
3c4577f
·
verified ·
1 Parent(s): cfb2ea0

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +116 -64
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # ⚙️ 后端逻辑/核心服务端.py (Hugging Face Spaces app.py)
2
  from fastapi import FastAPI, HTTPException, File, UploadFile, Form
3
  from fastapi.middleware.cors import CORSMiddleware
4
  from pydantic import BaseModel
@@ -37,10 +37,7 @@ async def upload_file(file: UploadFile = File(...), file_type: str = Form(...)):
37
  db.save_file(full_path_in_repo, content)
38
  url = f"https://huggingface.co/datasets/{db.DATASET_REPO_ID}/resolve/main/{full_path_in_repo}"
39
 
40
- return {
41
- "status": "success", "url": url,
42
- "display_name": original_name, "hashed_name": new_filename
43
- }
44
 
45
  # --- 数据模型 ---
46
  class UserRegister(BaseModel):
@@ -60,7 +57,6 @@ class UserLogin(BaseModel):
60
  account: str
61
  password: str
62
 
63
- # 【新增阶段一】:用户资料更新模型
64
  class UserUpdate(BaseModel):
65
  name: Optional[str] = None
66
  intro: Optional[str] = None
@@ -70,7 +66,6 @@ class UserUpdate(BaseModel):
70
  gender: Optional[str] = None
71
  avatarDataUrl: Optional[str] = None
72
 
73
- # 【新增阶段一】:修改密码模型
74
  class PasswordReset(BaseModel):
75
  old_password: str
76
  new_password: str
@@ -103,107 +98,107 @@ class FollowToggle(BaseModel):
103
  target_account: str
104
  is_active: bool
105
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  # --- 1. 用户系统 ---
107
  @app.post("/api/users/register")
108
  async def register_user(user: UserRegister):
109
  users_db = db.load_data("users.json", default_data={})
110
-
111
  if user.account in users_db: raise HTTPException(status_code=400, detail="该账号已被注册")
112
- for existing_user in users_db.values():
113
- if existing_user.get("email") == user.email: raise HTTPException(status_code=400, detail="该邮箱已被绑定")
114
- if existing_user.get("phone") == user.phone: raise HTTPException(status_code=400, detail="该手机号已被绑定")
115
-
116
  new_user = user.dict()
117
- new_user.update({
118
- "created_at": int(time.time()),
119
- "followers": [], "following": [],
120
- "privacy": {"follows": False, "likes": False, "favorites": False, "downloads": False}
121
- })
122
-
123
  users_db[user.account] = new_user
124
  db.save_data("users.json", users_db)
125
-
126
- safe_user_data = {k: v for k, v in new_user.items() if k != "password"}
127
- return {"status": "success", "message": "注册成功", "data": safe_user_data}
128
 
129
  @app.post("/api/users/login")
130
  async def login_user(user: UserLogin):
131
  users_db = db.load_data("users.json", default_data={})
132
- if user.account not in users_db: raise HTTPException(status_code=404, detail="账号不存在,请检查或先注册")
133
  user_data = users_db[user.account]
134
  if user_data.get("password") != user.password: raise HTTPException(status_code=401, detail="密码错误")
135
-
136
- return {
137
- "status": "success", "token": f"mock_token_{user.account}",
138
- "account": user.account, "name": user_data["name"],
139
- "avatar": user_data.get("avatarDataUrl", "https://via.placeholder.com/150")
140
- }
141
 
142
  @app.get("/api/users/{account}")
143
  async def get_user_profile(account: str):
144
  users_db = db.load_data("users.json", default_data={})
145
  if account not in users_db: raise HTTPException(status_code=404, detail="用户不存在")
146
-
147
  user_data = users_db[account]
148
  items_db = db.load_data("items.json", default_data=[])
149
  user_items = [item for item in items_db if item.get("author") == account]
150
-
151
  user_data["receivedLikes"] = sum(item.get("likes", 0) for item in user_items)
152
  user_data["receivedFavorites"] = sum(item.get("favorites", 0) for item in user_items)
153
  user_data["receivedUses"] = sum(item.get("uses", 0) for item in user_items)
154
-
155
- safe_user_data = {k: v for k, v in user_data.items() if k != "password"}
156
- return {"status": "success", "data": safe_user_data}
157
 
158
- # 【新增阶段一】:全量更新用户资料
159
  @app.put("/api/users/{account}")
160
  async def update_user_profile(account: str, update_data: UserUpdate):
161
  users_db = db.load_data("users.json", default_data={})
162
  if account not in users_db: raise HTTPException(status_code=404, detail="用户不存在")
163
-
164
  user = users_db[account]
165
- update_dict = update_data.dict(exclude_unset=True) # 仅更新传入的字段
166
-
167
  for k, v in update_dict.items():
168
- if v is not None:
169
- user[k] = v
170
-
171
  db.save_data("users.json", users_db)
172
- safe_user_data = {k: v for k, v in user.items() if k != "password"}
173
- return {"status": "success", "message": "资料更新成功", "data": safe_user_data}
174
 
175
- # 【新增阶段一】:修改账号密码
176
  @app.post("/api/users/{account}/reset-password")
177
  async def reset_password(account: str, pwd_data: PasswordReset):
178
  users_db = db.load_data("users.json", default_data={})
179
  if account not in users_db: raise HTTPException(status_code=404, detail="用户不存在")
180
-
181
  user = users_db[account]
182
- if user.get("password") != pwd_data.old_password:
183
- raise HTTPException(status_code=401, detail="原密码错误,修改失败")
184
-
185
  user["password"] = pwd_data.new_password
186
  db.save_data("users.json", users_db)
187
- return {"status": "success", "message": "密码修改成功"}
188
 
189
  @app.post("/api/users/follow")
190
  async def toggle_follow(follow: FollowToggle):
191
  users_db = db.load_data("users.json", default_data={})
192
  if follow.target_account not in users_db or follow.user_id not in users_db: raise HTTPException(status_code=404, detail="用户不存在")
193
-
194
- target_user = users_db[follow.target_account]
195
- current_user = users_db[follow.user_id]
196
-
197
- target_followers = target_user.setdefault("followers", [])
198
- current_following = current_user.setdefault("following", [])
199
 
200
  if follow.is_active:
201
- if follow.user_id not in target_followers: target_followers.append(follow.user_id)
 
 
 
202
  if follow.target_account not in current_following: current_following.append(follow.target_account)
203
  else:
204
  if follow.user_id in target_followers: target_followers.remove(follow.user_id)
205
  if follow.target_account in current_following: current_following.remove(follow.target_account)
206
-
207
  db.save_data("users.json", users_db)
208
  return {"status": "success"}
209
 
@@ -211,7 +206,13 @@ async def toggle_follow(follow: FollowToggle):
211
  @app.get("/api/items")
212
  async def get_items(type: str = "tool", sort: str = "time", limit: int = 20):
213
  items_db = db.load_data("items.json", default_data=[])
 
214
  filtered_items = [item for item in items_db if item.get("type") == type]
 
 
 
 
 
215
  if sort == "likes": filtered_items.sort(key=lambda x: x.get("likes", 0), reverse=True)
216
  elif sort == "favorites": filtered_items.sort(key=lambda x: x.get("favorites", 0), reverse=True)
217
  elif sort == "downloads": filtered_items.sort(key=lambda x: x.get("uses", 0), reverse=True)
@@ -222,6 +223,7 @@ async def get_items(type: str = "tool", sort: str = "time", limit: int = 20):
222
  async def get_creators(sort: str = "downloads", limit: int = 20):
223
  users_db = db.load_data("users.json", default_data={})
224
  items_db = db.load_data("items.json", default_data=[])
 
225
 
226
  creators = []
227
  for account, u in users_db.items():
@@ -237,6 +239,7 @@ async def get_creators(sort: str = "downloads", limit: int = 20):
237
  "shortDesc": u.get("intro", "这个人很懒,什么都没写..."), "fullDesc": u.get("intro", "这个人很懒,什么都没写..."),
238
  "likes": likes, "favorites": favorites, "downloads": uses, "toolsCount": tools_count, "appsCount": apps_count,
239
  "followers": len(u.get("followers", [])), "created_at": u.get("created_at", 0),
 
240
  "trendData": {"tools": [0,0,0,0,0, tools_count], "apps": [0,0,0,0,0, apps_count]}
241
  })
242
 
@@ -260,7 +263,7 @@ async def create_item(item: ItemCreate):
260
  db.save_data("items.json", items_db)
261
  return {"status": "success", "data": new_item}
262
 
263
- # --- 3. 社交与互动 ---
264
  @app.post("/api/interactions/toggle")
265
  async def toggle_interaction(interaction: InteractionToggle):
266
  items_db = db.load_data("items.json", default_data=[])
@@ -273,27 +276,55 @@ async def toggle_interaction(interaction: InteractionToggle):
273
 
274
  user_list = target_item[list_key]
275
  if interaction.is_active:
276
- if interaction.user_id not in user_list: user_list.append(interaction.user_id); target_item[count_key] += 1
 
 
 
 
 
 
 
277
  else:
278
  if interaction.user_id in user_list: user_list.remove(interaction.user_id); target_item[count_key] = max(0, target_item[count_key] - 1)
279
 
280
  db.save_data("items.json", items_db)
281
  return {"status": "success", "new_count": target_item[count_key]}
282
 
283
- # --- 4. 评论系统 ---
284
  @app.post("/api/comments")
285
  async def post_comment(comment: CommentCreate):
286
  comments_db = db.load_data("comments.json", default_data={})
 
 
 
 
 
287
  item_comments = comments_db.get(comment.item_id, [])
288
  new_comment = {
289
- "id": f"c_{int(time.time())}_{uuid.uuid4().hex[:6]}", "author": comment.author, "content": comment.content,
290
- "replyToUser": comment.reply_to_user, "isDeleted": False, "replies": [], "created_at": int(time.time())
 
 
291
  }
 
292
  if comment.parent_id:
293
  parent = next((c for c in item_comments if c["id"] == comment.parent_id), None)
294
- if parent: parent["replies"].append(new_comment)
 
 
 
 
295
  else: raise HTTPException(status_code=404, detail="找不到要回复的评论")
296
- else: item_comments.append(new_comment)
 
 
 
 
 
 
 
 
 
297
  comments_db[comment.item_id] = item_comments
298
  db.save_data("comments.json", comments_db)
299
  return {"status": "success", "data": new_comment}
@@ -314,4 +345,25 @@ async def soft_delete_comment(item_id: str, comment_id: str, author: str):
314
  if find_and_delete(item_comments):
315
  db.save_data("comments.json", comments_db)
316
  return {"status": "success", "message": "评论已删除"}
317
- raise HTTPException(status_code=404, detail="找不到该评论")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ⚙️ 后端逻辑/核心服务端.py
2
  from fastapi import FastAPI, HTTPException, File, UploadFile, Form
3
  from fastapi.middleware.cors import CORSMiddleware
4
  from pydantic import BaseModel
 
37
  db.save_file(full_path_in_repo, content)
38
  url = f"https://huggingface.co/datasets/{db.DATASET_REPO_ID}/resolve/main/{full_path_in_repo}"
39
 
40
+ return {"status": "success", "url": url, "display_name": original_name, "hashed_name": new_filename}
 
 
 
41
 
42
  # --- 数据模型 ---
43
  class UserRegister(BaseModel):
 
57
  account: str
58
  password: str
59
 
 
60
  class UserUpdate(BaseModel):
61
  name: Optional[str] = None
62
  intro: Optional[str] = None
 
66
  gender: Optional[str] = None
67
  avatarDataUrl: Optional[str] = None
68
 
 
69
  class PasswordReset(BaseModel):
70
  old_password: str
71
  new_password: str
 
98
  target_account: str
99
  is_active: bool
100
 
101
+ # 【核心新增】:私信数据模型
102
+ class PrivateMessage(BaseModel):
103
+ sender: str
104
+ receiver: str
105
+ content: str
106
+
107
+ # --- 消息分发引擎 ---
108
+ def add_notification(target_account: str, notif_data: dict):
109
+ from_user = notif_data.get("from_user")
110
+ if target_account == from_user or not target_account:
111
+ return # 不给自己发通知
112
+
113
+ users_db = db.load_data("users.json", default_data={})
114
+ user_info = users_db.get(from_user, {})
115
+
116
+ notif = {
117
+ "id": f"msg_{int(time.time())}_{uuid.uuid4().hex[:6]}",
118
+ "type": notif_data.get("type"), # like, favorite, comment, reply, follow, private
119
+ "from_user": from_user,
120
+ "from_name": user_info.get("name", from_user),
121
+ "from_avatar": user_info.get("avatarDataUrl", "https://via.placeholder.com/150"),
122
+ "target_item_id": notif_data.get("target_item_id", ""),
123
+ "target_item_title": notif_data.get("target_item_title", ""),
124
+ "content": notif_data.get("content", ""),
125
+ "is_read": False,
126
+ "created_at": int(time.time())
127
+ }
128
+
129
+ msgs_db = db.load_data("messages.json", default_data={})
130
+ if target_account not in msgs_db: msgs_db[target_account] = []
131
+ msgs_db[target_account].insert(0, notif)
132
+ db.save_data("messages.json", msgs_db)
133
+
134
  # --- 1. 用户系统 ---
135
  @app.post("/api/users/register")
136
  async def register_user(user: UserRegister):
137
  users_db = db.load_data("users.json", default_data={})
 
138
  if user.account in users_db: raise HTTPException(status_code=400, detail="该账号已被注册")
 
 
 
 
139
  new_user = user.dict()
140
+ new_user.update({"created_at": int(time.time()), "followers": [], "following": [], "privacy": {"follows": False, "likes": False, "favorites": False, "downloads": False}})
 
 
 
 
 
141
  users_db[user.account] = new_user
142
  db.save_data("users.json", users_db)
143
+ return {"status": "success", "message": "注册成功", "data": {k: v for k, v in new_user.items() if k != "password"}}
 
 
144
 
145
  @app.post("/api/users/login")
146
  async def login_user(user: UserLogin):
147
  users_db = db.load_data("users.json", default_data={})
148
+ if user.account not in users_db: raise HTTPException(status_code=404, detail="账号不存在")
149
  user_data = users_db[user.account]
150
  if user_data.get("password") != user.password: raise HTTPException(status_code=401, detail="密码错误")
151
+ return {"status": "success", "token": f"mock_token_{user.account}", "account": user.account, "name": user_data["name"], "avatar": user_data.get("avatarDataUrl", "https://via.placeholder.com/150")}
 
 
 
 
 
152
 
153
  @app.get("/api/users/{account}")
154
  async def get_user_profile(account: str):
155
  users_db = db.load_data("users.json", default_data={})
156
  if account not in users_db: raise HTTPException(status_code=404, detail="用户不存在")
 
157
  user_data = users_db[account]
158
  items_db = db.load_data("items.json", default_data=[])
159
  user_items = [item for item in items_db if item.get("author") == account]
 
160
  user_data["receivedLikes"] = sum(item.get("likes", 0) for item in user_items)
161
  user_data["receivedFavorites"] = sum(item.get("favorites", 0) for item in user_items)
162
  user_data["receivedUses"] = sum(item.get("uses", 0) for item in user_items)
163
+ return {"status": "success", "data": {k: v for k, v in user_data.items() if k != "password"}}
 
 
164
 
 
165
  @app.put("/api/users/{account}")
166
  async def update_user_profile(account: str, update_data: UserUpdate):
167
  users_db = db.load_data("users.json", default_data={})
168
  if account not in users_db: raise HTTPException(status_code=404, detail="用户不存在")
 
169
  user = users_db[account]
170
+ update_dict = update_data.dict(exclude_unset=True)
 
171
  for k, v in update_dict.items():
172
+ if v is not None: user[k] = v
 
 
173
  db.save_data("users.json", users_db)
174
+ return {"status": "success", "data": {k: v for k, v in user.items() if k != "password"}}
 
175
 
 
176
  @app.post("/api/users/{account}/reset-password")
177
  async def reset_password(account: str, pwd_data: PasswordReset):
178
  users_db = db.load_data("users.json", default_data={})
179
  if account not in users_db: raise HTTPException(status_code=404, detail="用户不存在")
 
180
  user = users_db[account]
181
+ if user.get("password") != pwd_data.old_password: raise HTTPException(status_code=401, detail="原密码错误")
 
 
182
  user["password"] = pwd_data.new_password
183
  db.save_data("users.json", users_db)
184
+ return {"status": "success"}
185
 
186
  @app.post("/api/users/follow")
187
  async def toggle_follow(follow: FollowToggle):
188
  users_db = db.load_data("users.json", default_data={})
189
  if follow.target_account not in users_db or follow.user_id not in users_db: raise HTTPException(status_code=404, detail="用户不存在")
190
+ target_followers = users_db[follow.target_account].setdefault("followers", [])
191
+ current_following = users_db[follow.user_id].setdefault("following", [])
 
 
 
 
192
 
193
  if follow.is_active:
194
+ if follow.user_id not in target_followers:
195
+ target_followers.append(follow.user_id)
196
+ # 派发关注通知
197
+ add_notification(follow.target_account, {"type": "follow", "from_user": follow.user_id})
198
  if follow.target_account not in current_following: current_following.append(follow.target_account)
199
  else:
200
  if follow.user_id in target_followers: target_followers.remove(follow.user_id)
201
  if follow.target_account in current_following: current_following.remove(follow.target_account)
 
202
  db.save_data("users.json", users_db)
203
  return {"status": "success"}
204
 
 
206
  @app.get("/api/items")
207
  async def get_items(type: str = "tool", sort: str = "time", limit: int = 20):
208
  items_db = db.load_data("items.json", default_data=[])
209
+ comments_db = db.load_data("comments.json", default_data={})
210
  filtered_items = [item for item in items_db if item.get("type") == type]
211
+ for item in filtered_items:
212
+ # 动态挂载评论区数据
213
+ item["commentsData"] = comments_db.get(item["id"], [])
214
+ item["comments"] = len(item["commentsData"])
215
+
216
  if sort == "likes": filtered_items.sort(key=lambda x: x.get("likes", 0), reverse=True)
217
  elif sort == "favorites": filtered_items.sort(key=lambda x: x.get("favorites", 0), reverse=True)
218
  elif sort == "downloads": filtered_items.sort(key=lambda x: x.get("uses", 0), reverse=True)
 
223
  async def get_creators(sort: str = "downloads", limit: int = 20):
224
  users_db = db.load_data("users.json", default_data={})
225
  items_db = db.load_data("items.json", default_data=[])
226
+ comments_db = db.load_data("comments.json", default_data={})
227
 
228
  creators = []
229
  for account, u in users_db.items():
 
239
  "shortDesc": u.get("intro", "这个人很懒,什么都没写..."), "fullDesc": u.get("intro", "这个人很懒,什么都没写..."),
240
  "likes": likes, "favorites": favorites, "downloads": uses, "toolsCount": tools_count, "appsCount": apps_count,
241
  "followers": len(u.get("followers", [])), "created_at": u.get("created_at", 0),
242
+ "commentsData": comments_db.get(account, []), # 挂载留言板数据
243
  "trendData": {"tools": [0,0,0,0,0, tools_count], "apps": [0,0,0,0,0, apps_count]}
244
  })
245
 
 
263
  db.save_data("items.json", items_db)
264
  return {"status": "success", "data": new_item}
265
 
266
+ # --- 3. 社交与互动 (点赞/收藏防抖与通知派发) ---
267
  @app.post("/api/interactions/toggle")
268
  async def toggle_interaction(interaction: InteractionToggle):
269
  items_db = db.load_data("items.json", default_data=[])
 
276
 
277
  user_list = target_item[list_key]
278
  if interaction.is_active:
279
+ if interaction.user_id not in user_list:
280
+ user_list.append(interaction.user_id)
281
+ target_item[count_key] += 1
282
+ # 派发点赞/收藏通知给作者
283
+ add_notification(target_item.get("author", ""), {
284
+ "type": interaction.action_type, "from_user": interaction.user_id,
285
+ "target_item_id": target_item["id"], "target_item_title": target_item["title"]
286
+ })
287
  else:
288
  if interaction.user_id in user_list: user_list.remove(interaction.user_id); target_item[count_key] = max(0, target_item[count_key] - 1)
289
 
290
  db.save_data("items.json", items_db)
291
  return {"status": "success", "new_count": target_item[count_key]}
292
 
293
+ # --- 4. 评论系统与消息 ---
294
  @app.post("/api/comments")
295
  async def post_comment(comment: CommentCreate):
296
  comments_db = db.load_data("comments.json", default_data={})
297
+ users_db = db.load_data("users.json", default_data={})
298
+
299
+ author_info = users_db.get(comment.author, {})
300
+ reply_name = users_db.get(comment.reply_to_user, {}).get("name", comment.reply_to_user) if comment.reply_to_user else None
301
+
302
  item_comments = comments_db.get(comment.item_id, [])
303
  new_comment = {
304
+ "id": f"c_{int(time.time())}_{uuid.uuid4().hex[:6]}", "author": comment.author,
305
+ "authorName": author_info.get("name", comment.author), "avatar": author_info.get("avatarDataUrl", "https://via.placeholder.com/150"),
306
+ "content": comment.content, "replyToUser": comment.reply_to_user, "replyToUserName": reply_name,
307
+ "isDeleted": False, "replies": [], "created_at": int(time.time())
308
  }
309
+
310
  if comment.parent_id:
311
  parent = next((c for c in item_comments if c["id"] == comment.parent_id), None)
312
+ if parent:
313
+ parent["replies"].append(new_comment)
314
+ # 通知被回复者
315
+ if comment.reply_to_user:
316
+ add_notification(comment.reply_to_user, {"type": "reply", "from_user": comment.author, "target_item_id": comment.item_id, "target_item_title": "收到新的回复", "content": comment.content})
317
  else: raise HTTPException(status_code=404, detail="找不到要回复的评论")
318
+ else:
319
+ item_comments.append(new_comment)
320
+ # 通知作品作者 或 留言板主人
321
+ items_db = db.load_data("items.json", default_data=[])
322
+ target_item = next((item for item in items_db if item["id"] == comment.item_id), None)
323
+ if target_item:
324
+ add_notification(target_item.get("author", ""), {"type": "comment", "from_user": comment.author, "target_item_id": comment.item_id, "target_item_title": target_item["title"], "content": comment.content})
325
+ elif comment.item_id in users_db:
326
+ add_notification(comment.item_id, {"type": "comment", "from_user": comment.author, "target_item_id": comment.item_id, "target_item_title": "您的个人留言板", "content": comment.content})
327
+
328
  comments_db[comment.item_id] = item_comments
329
  db.save_data("comments.json", comments_db)
330
  return {"status": "success", "data": new_comment}
 
345
  if find_and_delete(item_comments):
346
  db.save_data("comments.json", comments_db)
347
  return {"status": "success", "message": "评论已删除"}
348
+ raise HTTPException(status_code=404, detail="找不到该评论")
349
+
350
+ @app.post("/api/messages/private")
351
+ async def send_private_message(msg: PrivateMessage):
352
+ add_notification(msg.receiver, {"type": "private", "from_user": msg.sender, "content": msg.content})
353
+ return {"status": "success"}
354
+
355
+ @app.get("/api/messages/{account}")
356
+ async def get_messages(account: str):
357
+ msgs_db = db.load_data("messages.json", default_data={})
358
+ user_msgs = msgs_db.get(account, [])
359
+ unread_count = sum(1 for m in user_msgs if not m.get("is_read"))
360
+ return {"status": "success", "data": user_msgs, "unread_count": unread_count}
361
+
362
+ @app.post("/api/messages/{account}/read")
363
+ async def mark_messages_read(account: str):
364
+ msgs_db = db.load_data("messages.json", default_data={})
365
+ user_msgs = msgs_db.get(account, [])
366
+ for m in user_msgs: m["is_read"] = True
367
+ msgs_db[account] = user_msgs
368
+ db.save_data("messages.json", msgs_db)
369
+ return {"status": "success"}