ZHIWEI666 commited on
Commit
088dffd
·
verified ·
1 Parent(s): 1fa72c8

Upload 10 files

Browse files
Files changed (5) hide show
  1. app.py +10 -4
  2. router_comments.py +83 -0
  3. router_items.py +57 -0
  4. router_messages.py +106 -0
  5. router_users.py +88 -0
app.py CHANGED
@@ -4,8 +4,11 @@ from fastapi.middleware.cors import CORSMiddleware
4
  import hashlib
5
  import 数据库连接 as db
6
 
7
- # 引入抽离出去的业务路由
8
- from routers import router
 
 
 
9
 
10
  app = FastAPI(title="ComfyUI Ranking Community API")
11
 
@@ -17,8 +20,11 @@ app.add_middleware(
17
  allow_headers=["*"],
18
  )
19
 
20
- # 挂载业务路由
21
- app.include_router(router)
 
 
 
22
 
23
  @app.get("/")
24
  def read_root():
 
4
  import hashlib
5
  import 数据库连接 as db
6
 
7
+ # 引入拆分后四大业务模块
8
+ from router_users import router as users_router
9
+ from router_items import router as items_router
10
+ from router_comments import router as comments_router
11
+ from router_messages import router as messages_router
12
 
13
  app = FastAPI(title="ComfyUI Ranking Community API")
14
 
 
20
  allow_headers=["*"],
21
  )
22
 
23
+ # 挂载并聚合所有业务路由
24
+ app.include_router(users_router)
25
+ app.include_router(items_router)
26
+ app.include_router(comments_router)
27
+ app.include_router(messages_router)
28
 
29
  @app.get("/")
30
  def read_root():
router_comments.py ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # router_comments.py
2
+ from fastapi import APIRouter, HTTPException
3
+ import time
4
+ import uuid
5
+ import 数据库连接 as db
6
+ from notifications import add_notification
7
+ from models import InteractionToggle, CommentCreate
8
+
9
+ router = APIRouter()
10
+
11
+ @router.post("/api/interactions/toggle")
12
+ async def toggle_interaction(interaction: InteractionToggle):
13
+ items_db = db.load_data("items.json", default_data=[])
14
+ target_item = next((item for item in items_db if item["id"] == interaction.item_id), None)
15
+ if not target_item: raise HTTPException(status_code=404, detail="目标存在问题")
16
+
17
+ list_key = f"{interaction.action_type}d_by"
18
+ count_key = "likes" if interaction.action_type == "like" else "favorites"
19
+ if list_key not in target_item: target_item[list_key] = []; target_item[count_key] = 0
20
+
21
+ user_list = target_item[list_key]
22
+ if interaction.is_active:
23
+ if interaction.user_id not in user_list:
24
+ user_list.append(interaction.user_id)
25
+ target_item[count_key] += 1
26
+ add_notification(target_item.get("author", ""), {"type": interaction.action_type, "from_user": interaction.user_id, "target_item_id": target_item["id"], "target_item_title": target_item["title"]})
27
+ else:
28
+ if interaction.user_id in user_list:
29
+ user_list.remove(interaction.user_id)
30
+ target_item[count_key] = max(0, target_item[count_key] - 1)
31
+ db.save_data("items.json", items_db)
32
+ return {"status": "success", "new_count": target_item[count_key]}
33
+
34
+ @router.post("/api/comments")
35
+ async def post_comment(comment: CommentCreate):
36
+ comments_db = db.load_data("comments.json", default_data={})
37
+ users_db = db.load_data("users.json", default_data={})
38
+ author_info = users_db.get(comment.author, {})
39
+ reply_name = users_db.get(comment.reply_to_user, {}).get("name", comment.reply_to_user) if comment.reply_to_user else None
40
+
41
+ item_comments = comments_db.get(comment.item_id, [])
42
+ new_comment = {
43
+ "id": f"c_{int(time.time())}_{uuid.uuid4().hex[:6]}", "author": comment.author,
44
+ "authorName": author_info.get("name", comment.author), "avatar": author_info.get("avatarDataUrl", "https://via.placeholder.com/150"),
45
+ "content": comment.content, "replyToUser": comment.reply_to_user, "replyToUserName": reply_name,
46
+ "isDeleted": False, "replies": [], "created_at": int(time.time())
47
+ }
48
+
49
+ if comment.parent_id:
50
+ parent = next((c for c in item_comments if c["id"] == comment.parent_id), None)
51
+ if parent:
52
+ parent["replies"].append(new_comment)
53
+ if comment.reply_to_user:
54
+ add_notification(comment.reply_to_user, {"type": "reply", "from_user": comment.author, "target_item_id": comment.item_id, "target_item_title": "收到新的回复", "content": comment.content})
55
+ else: raise HTTPException(status_code=404, detail="找不到要回复的评论")
56
+ else:
57
+ item_comments.append(new_comment)
58
+ items_db = db.load_data("items.json", default_data=[])
59
+ target_item = next((item for item in items_db if item["id"] == comment.item_id), None)
60
+ if target_item:
61
+ 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})
62
+ elif comment.item_id in users_db:
63
+ add_notification(comment.item_id, {"type": "comment", "from_user": comment.author, "target_item_id": comment.item_id, "target_item_title": "您的个人留言板", "content": comment.content})
64
+
65
+ comments_db[comment.item_id] = item_comments
66
+ db.save_data("comments.json", comments_db)
67
+ return {"status": "success", "data": new_comment}
68
+
69
+ @router.delete("/api/comments/{item_id}/{comment_id}")
70
+ async def soft_delete_comment(item_id: str, comment_id: str, author: str):
71
+ comments_db = db.load_data("comments.json", default_data={})
72
+ item_comments = comments_db.get(item_id, [])
73
+ def find_and_delete(comments_list):
74
+ for c in comments_list:
75
+ if c["id"] == comment_id:
76
+ if c["author"] != author: raise HTTPException(status_code=403, detail="无权删除他人的评论")
77
+ c["isDeleted"] = True; c["content"] = ""; return True
78
+ if "replies" in c and find_and_delete(c["replies"]): return True
79
+ return False
80
+ if find_and_delete(item_comments):
81
+ db.save_data("comments.json", comments_db)
82
+ return {"status": "success"}
83
+ raise HTTPException(status_code=404, detail="找不到该评论")
router_items.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # router_items.py
2
+ from fastapi import APIRouter
3
+ import time
4
+ import uuid
5
+ import 数据库连接 as db
6
+ from models import ItemCreate
7
+
8
+ router = APIRouter()
9
+
10
+ @router.get("/api/items")
11
+ async def get_items(type: str = "tool", sort: str = "time", limit: int = 20):
12
+ items_db = db.load_data("items.json", default_data=[])
13
+ comments_db = db.load_data("comments.json", default_data={})
14
+ filtered_items = [item for item in items_db if item.get("type") == type]
15
+ for item in filtered_items:
16
+ item["commentsData"] = comments_db.get(item["id"], [])
17
+ item["comments"] = len(item["commentsData"])
18
+ if sort == "likes": filtered_items.sort(key=lambda x: x.get("likes", 0), reverse=True)
19
+ elif sort == "favorites": filtered_items.sort(key=lambda x: x.get("favorites", 0), reverse=True)
20
+ elif sort == "downloads": filtered_items.sort(key=lambda x: x.get("uses", 0), reverse=True)
21
+ else: filtered_items.sort(key=lambda x: x.get("created_at", 0), reverse=True)
22
+ return {"status": "success", "data": filtered_items[:limit]}
23
+
24
+ @router.get("/api/creators")
25
+ async def get_creators(sort: str = "downloads", limit: int = 20):
26
+ users_db = db.load_data("users.json", default_data={})
27
+ items_db = db.load_data("items.json", default_data=[])
28
+ comments_db = db.load_data("comments.json", default_data={})
29
+ creators = []
30
+ for account, u in users_db.items():
31
+ u_items = [i for i in items_db if i.get("author") == account]
32
+ tools_count = sum(1 for i in u_items if i.get("type") == "tool")
33
+ apps_count = sum(1 for i in u_items if i.get("type") == "app")
34
+ creators.append({
35
+ "account": account, "name": u.get("name", account), "avatar": u.get("avatarDataUrl", "https://via.placeholder.com/150"),
36
+ "shortDesc": u.get("intro", "这个人很懒,什么都没写..."), "fullDesc": u.get("intro", "这个人很懒,什么都没写..."),
37
+ "likes": sum(i.get("likes", 0) for i in u_items), "favorites": sum(i.get("favorites", 0) for i in u_items), "downloads": sum(i.get("uses", 0) for i in u_items),
38
+ "toolsCount": tools_count, "appsCount": apps_count, "followers": len(u.get("followers", [])), "created_at": u.get("created_at", 0),
39
+ "commentsData": comments_db.get(account, []), "trendData": {"tools": [0,0,0,0,0, tools_count], "apps": [0,0,0,0,0, apps_count]}
40
+ })
41
+ if sort == "likes": creators.sort(key=lambda x: x.get("likes", 0), reverse=True)
42
+ elif sort == "favorites": creators.sort(key=lambda x: x.get("favorites", 0), reverse=True)
43
+ elif sort == "downloads": creators.sort(key=lambda x: x.get("downloads", 0), reverse=True)
44
+ else: creators.sort(key=lambda x: x.get("created_at", 0), reverse=True)
45
+ return {"status": "success", "data": creators[:limit]}
46
+
47
+ @router.post("/api/items")
48
+ async def create_item(item: ItemCreate):
49
+ items_db = db.load_data("items.json", default_data=[])
50
+ new_item = {
51
+ "id": f"{item.type}_{int(time.time())}_{uuid.uuid4().hex[:6]}", "type": item.type, "title": item.title, "author": item.author,
52
+ "shortDesc": item.shortDesc, "fullDesc": item.fullDesc, "link": item.link, "coverUrl": item.coverUrl, "price": item.price,
53
+ "likes": 0, "favorites": 0, "comments": 0, "uses": 0, "created_at": int(time.time()), "liked_by": [], "favorited_by": []
54
+ }
55
+ items_db.insert(0, new_item)
56
+ db.save_data("items.json", items_db)
57
+ return {"status": "success", "data": new_item}
router_messages.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # router_messages.py
2
+ from fastapi import APIRouter
3
+ import time
4
+ import uuid
5
+ import 数据库连接 as db
6
+ from notifications import add_notification
7
+ from models import PrivateMessage
8
+
9
+ router = APIRouter()
10
+
11
+ @router.post("/api/messages/private")
12
+ async def send_private_message(msg: PrivateMessage):
13
+ chats_db = db.load_data("chats.json", default_data={})
14
+ conv_id = f"{min(msg.sender, msg.receiver)}_{max(msg.sender, msg.receiver)}"
15
+ if conv_id not in chats_db: chats_db[conv_id] = []
16
+
17
+ chat_msg = {"id": f"chat_{int(time.time())}_{uuid.uuid4().hex[:6]}", "sender": msg.sender, "receiver": msg.receiver, "content": msg.content, "created_at": int(time.time()), "is_read": False}
18
+ chats_db[conv_id].append(chat_msg)
19
+ db.save_data("chats.json", chats_db)
20
+
21
+ add_notification(msg.receiver, {"type": "private", "from_user": msg.sender, "content": msg.content})
22
+ return {"status": "success"}
23
+
24
+ @router.get("/api/chats/{account}")
25
+ async def get_chat_list(account: str):
26
+ chats_db = db.load_data("chats.json", default_data={})
27
+ users_db = db.load_data("users.json", default_data={})
28
+ chat_list = []
29
+ now = int(time.time())
30
+ seven_days = 7 * 24 * 3600
31
+
32
+ for conv_id, msgs in chats_db.items():
33
+ accs = conv_id.split("_")
34
+ if account in accs and msgs:
35
+ # 列表中只统计有效消息
36
+ valid_msgs = [m for m in msgs if not m.get("is_read") or (now - m.get("created_at", 0) < seven_days)]
37
+ if valid_msgs:
38
+ target = accs[0] if accs[1] == account else accs[1]
39
+ target_info = users_db.get(target, {})
40
+ chat_list.append({
41
+ "target_account": target, "target_name": target_info.get("name", target),
42
+ "last_message": valid_msgs[-1]["content"], "last_time": valid_msgs[-1]["created_at"],
43
+ "unread": sum(1 for m in valid_msgs if m["receiver"] == account and not m.get("is_read"))
44
+ })
45
+ chat_list.sort(key=lambda x: x["last_time"], reverse=True)
46
+ return {"status": "success", "data": chat_list}
47
+
48
+ @router.get("/api/chats/{account}/{target}")
49
+ async def get_chat_history(account: str, target: str):
50
+ chats_db = db.load_data("chats.json", default_data={})
51
+ conv_id = f"{min(account, target)}_{max(account, target)}"
52
+ msgs = chats_db.get(conv_id, [])
53
+
54
+ now = int(time.time())
55
+ seven_days = 7 * 24 * 3600
56
+ valid_msgs = []
57
+ modified = False
58
+
59
+ for m in msgs:
60
+ # 【核心策略】:未读的永远保留,已读的超过 7 天直接抛弃
61
+ if not m.get("is_read") or (now - m.get("created_at", 0) < seven_days):
62
+ valid_msgs.append(m)
63
+ else:
64
+ modified = True
65
+
66
+ # 本次访问即为已读
67
+ if m["receiver"] == account and not m.get("is_read"):
68
+ m["is_read"] = True
69
+ modified = True
70
+
71
+ if modified or len(valid_msgs) != len(msgs):
72
+ chats_db[conv_id] = valid_msgs
73
+ db.save_data("chats.json", chats_db)
74
+
75
+ return {"status": "success", "data": valid_msgs}
76
+
77
+ @router.get("/api/messages/{account}")
78
+ async def get_messages(account: str):
79
+ msgs_db = db.load_data("messages.json", default_data={})
80
+ user_msgs = msgs_db.get(account, [])
81
+
82
+ now = int(time.time())
83
+ seven_days = 7 * 24 * 3600
84
+ valid = []
85
+ modified = False
86
+
87
+ for m in user_msgs:
88
+ if not m.get("is_read") or (now - m.get("created_at", 0) < seven_days):
89
+ valid.append(m)
90
+ else:
91
+ modified = True
92
+
93
+ if modified:
94
+ msgs_db[account] = valid
95
+ db.save_data("messages.json", msgs_db)
96
+
97
+ return {"status": "success", "data": valid, "unread_count": sum(1 for m in valid if not m.get("is_read"))}
98
+
99
+ @router.post("/api/messages/{account}/read")
100
+ async def mark_messages_read(account: str):
101
+ msgs_db = db.load_data("messages.json", default_data={})
102
+ user_msgs = msgs_db.get(account, [])
103
+ for m in user_msgs: m["is_read"] = True
104
+ msgs_db[account] = user_msgs
105
+ db.save_data("messages.json", msgs_db)
106
+ return {"status": "success"}
router_users.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # router_users.py
2
+ from fastapi import APIRouter, HTTPException
3
+ import time
4
+ import re
5
+ import 数据库连接 as db
6
+ from notifications import add_notification
7
+ from models import UserRegister, UserLogin, UserUpdate, PasswordReset, FollowToggle
8
+
9
+ router = APIRouter()
10
+
11
+ @router.post("/api/users/register")
12
+ async def register_user(user: UserRegister):
13
+ users_db = db.load_data("users.json", default_data={})
14
+ if len(user.account) <= 5: raise HTTPException(status_code=400, detail="账号必须大于5个字符")
15
+ if not re.match(r'^[a-zA-Z0-9_]{6,20}$', user.account): raise HTTPException(status_code=400, detail="账号仅支持大小写英文字母、数字及下划线")
16
+ if len(user.password) < 6: raise HTTPException(status_code=400, detail="密码必须大于等于6个字符")
17
+ if not re.match(r'^[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};\':"\\|,.<>\/?]{6,}$', user.password): raise HTTPException(status_code=400, detail="密码包含不支持的特殊字符")
18
+ if user.intro and len(user.intro) > 100: raise HTTPException(status_code=400, detail="个人介绍不能超过100个字符")
19
+ if user.account in users_db: raise HTTPException(status_code=400, detail="该账号已被注册")
20
+ for existing_user in users_db.values():
21
+ if existing_user.get("email") == user.email: raise HTTPException(status_code=400, detail="该邮箱已被绑定")
22
+ if existing_user.get("phone") == user.phone: raise HTTPException(status_code=400, detail="该手机号已被绑定")
23
+
24
+ new_user = user.dict()
25
+ new_user.update({"created_at": int(time.time()), "followers": [], "following": [], "privacy": {"follows": False, "likes": False, "favorites": False, "downloads": False}})
26
+ users_db[user.account] = new_user
27
+ db.save_data("users.json", users_db)
28
+ return {"status": "success", "message": "注册成功", "data": {k: v for k, v in new_user.items() if k != "password"}}
29
+
30
+ @router.post("/api/users/login")
31
+ async def login_user(user: UserLogin):
32
+ users_db = db.load_data("users.json", default_data={})
33
+ if user.account not in users_db: raise HTTPException(status_code=404, detail="账号不存在")
34
+ user_data = users_db[user.account]
35
+ if user_data.get("password") != user.password: raise HTTPException(status_code=401, detail="密码错误")
36
+ 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")}
37
+
38
+ @router.get("/api/users/{account}")
39
+ async def get_user_profile(account: str):
40
+ users_db = db.load_data("users.json", default_data={})
41
+ if account not in users_db: raise HTTPException(status_code=404, detail="用户不存在")
42
+ user_data = users_db[account]
43
+ items_db = db.load_data("items.json", default_data=[])
44
+ user_items = [item for item in items_db if item.get("author") == account]
45
+ user_data["receivedLikes"] = sum(item.get("likes", 0) for item in user_items)
46
+ user_data["receivedFavorites"] = sum(item.get("favorites", 0) for item in user_items)
47
+ user_data["receivedUses"] = sum(item.get("uses", 0) for item in user_items)
48
+ return {"status": "success", "data": {k: v for k, v in user_data.items() if k != "password"}}
49
+
50
+ @router.put("/api/users/{account}")
51
+ async def update_user_profile(account: str, update_data: UserUpdate):
52
+ users_db = db.load_data("users.json", default_data={})
53
+ if account not in users_db: raise HTTPException(status_code=404, detail="用户不存在")
54
+ if update_data.intro and len(update_data.intro) > 100: raise HTTPException(status_code=400, detail="个人介绍不能超过100个字符")
55
+ user = users_db[account]
56
+ for k, v in update_data.dict(exclude_unset=True).items():
57
+ if v is not None: user[k] = v
58
+ db.save_data("users.json", users_db)
59
+ return {"status": "success", "data": {k: v for k, v in user.items() if k != "password"}}
60
+
61
+ @router.post("/api/users/{account}/reset-password")
62
+ async def reset_password(account: str, pwd_data: PasswordReset):
63
+ users_db = db.load_data("users.json", default_data={})
64
+ if account not in users_db: raise HTTPException(status_code=404, detail="用户不存在")
65
+ if len(pwd_data.new_password) < 6: raise HTTPException(status_code=400, detail="新密码必须大于等于6个字符")
66
+ if not re.match(r'^[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};\':"\\|,.<>\/?]{6,}$', pwd_data.new_password): raise HTTPException(status_code=400, detail="新密码包含不支持的特殊字符")
67
+ user = users_db[account]
68
+ if user.get("password") != pwd_data.old_password: raise HTTPException(status_code=401, detail="原密码错误")
69
+ user["password"] = pwd_data.new_password
70
+ db.save_data("users.json", users_db)
71
+ return {"status": "success"}
72
+
73
+ @router.post("/api/users/follow")
74
+ async def toggle_follow(follow: FollowToggle):
75
+ users_db = db.load_data("users.json", default_data={})
76
+ if follow.target_account not in users_db or follow.user_id not in users_db: raise HTTPException(status_code=404, detail="用户不存在")
77
+ target_followers = users_db[follow.target_account].setdefault("followers", [])
78
+ current_following = users_db[follow.user_id].setdefault("following", [])
79
+ if follow.is_active:
80
+ if follow.user_id not in target_followers:
81
+ target_followers.append(follow.user_id)
82
+ add_notification(follow.target_account, {"type": "follow", "from_user": follow.user_id})
83
+ if follow.target_account not in current_following: current_following.append(follow.target_account)
84
+ else:
85
+ if follow.user_id in target_followers: target_followers.remove(follow.user_id)
86
+ if follow.target_account in current_following: current_following.remove(follow.target_account)
87
+ db.save_data("users.json", users_db)
88
+ return {"status": "success"}