合并JWL,WZY,TRM代码
Change-Id: Ifb4fcad3c06733e1e005e7d8d9403e3561010fb4
diff --git a/Merge/back_wzy/routes/__init__.py b/Merge/back_wzy/routes/__init__.py
new file mode 100644
index 0000000..5410dd3
--- /dev/null
+++ b/Merge/back_wzy/routes/__init__.py
@@ -0,0 +1,4 @@
+# routes/__init__.py
+from flask import Blueprint
+
+# 可以在这里统一注册蓝图,也可以直接在 app.py 中 import
diff --git a/Merge/back_wzy/routes/__pycache__/__init__.cpython-310.pyc b/Merge/back_wzy/routes/__pycache__/__init__.cpython-310.pyc
new file mode 100644
index 0000000..fd9f45b
--- /dev/null
+++ b/Merge/back_wzy/routes/__pycache__/__init__.cpython-310.pyc
Binary files differ
diff --git a/Merge/back_wzy/routes/__pycache__/__init__.cpython-312.pyc b/Merge/back_wzy/routes/__pycache__/__init__.cpython-312.pyc
new file mode 100644
index 0000000..acde7ed
--- /dev/null
+++ b/Merge/back_wzy/routes/__pycache__/__init__.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_wzy/routes/__pycache__/comments.cpython-310.pyc b/Merge/back_wzy/routes/__pycache__/comments.cpython-310.pyc
new file mode 100644
index 0000000..087a126
--- /dev/null
+++ b/Merge/back_wzy/routes/__pycache__/comments.cpython-310.pyc
Binary files differ
diff --git a/Merge/back_wzy/routes/__pycache__/comments.cpython-312.pyc b/Merge/back_wzy/routes/__pycache__/comments.cpython-312.pyc
new file mode 100644
index 0000000..4bd83ee
--- /dev/null
+++ b/Merge/back_wzy/routes/__pycache__/comments.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_wzy/routes/__pycache__/posts.cpython-310.pyc b/Merge/back_wzy/routes/__pycache__/posts.cpython-310.pyc
new file mode 100644
index 0000000..a22b03e
--- /dev/null
+++ b/Merge/back_wzy/routes/__pycache__/posts.cpython-310.pyc
Binary files differ
diff --git a/Merge/back_wzy/routes/__pycache__/posts.cpython-312.pyc b/Merge/back_wzy/routes/__pycache__/posts.cpython-312.pyc
new file mode 100644
index 0000000..a957747
--- /dev/null
+++ b/Merge/back_wzy/routes/__pycache__/posts.cpython-312.pyc
Binary files differ
diff --git a/Merge/back_wzy/routes/comments.py b/Merge/back_wzy/routes/comments.py
new file mode 100644
index 0000000..2d5b654
--- /dev/null
+++ b/Merge/back_wzy/routes/comments.py
@@ -0,0 +1,46 @@
+# routes/comments.py
+from flask import Blueprint, request, jsonify, abort
+from extensions import db
+from models.comment import Comment
+from models.behavior import Behavior
+
+comments_bp = Blueprint('comments', __name__)
+
+@comments_bp.route('', methods=['POST'])
+def add_comment(post_id):
+ data = request.get_json() or {}
+ user_id = data.get('user_id')
+ content = data.get('content')
+ if not user_id or not content:
+ return jsonify({'error': 'user_id and content required'}), 400
+
+ comment = Comment(
+ post_id=post_id,
+ user_id=user_id,
+ content=content,
+ parent_id=data.get('parent_id')
+ )
+ db.session.add(comment)
+ # 记录行为
+ beh = Behavior(user_id=user_id, post_id=post_id, type='comment')
+ db.session.add(beh)
+ db.session.commit()
+ return jsonify({'id': comment.id}), 201
+
+@comments_bp.route('', methods=['GET'])
+def list_comments(post_id):
+ def serialize(c):
+ return {
+ 'id': c.id,
+ 'user_id': c.user_id,
+ 'content': c.content,
+ 'created_at': c.created_at.isoformat(),
+ 'replies': [serialize(r) for r in c.replies]
+ }
+
+ comments = Comment.query.filter_by(
+ post_id=post_id,
+ status='active',
+ parent_id=None
+ ).order_by(Comment.created_at.asc()).all()
+ return jsonify([serialize(c) for c in comments])
diff --git a/Merge/back_wzy/routes/posts.py b/Merge/back_wzy/routes/posts.py
new file mode 100644
index 0000000..e01bdd8
--- /dev/null
+++ b/Merge/back_wzy/routes/posts.py
@@ -0,0 +1,150 @@
+# routes/posts.py
+from flask import Blueprint, request, jsonify, abort
+from extensions import db
+from models.post import Post
+from models.behavior import Behavior
+
+posts_bp = Blueprint('posts', __name__)
+
+@posts_bp.route('', methods=['POST'])
+def create_post():
+ data = request.get_json() or {}
+ post = Post(**data)
+ db.session.add(post)
+ db.session.commit()
+ return jsonify({'id': post.id}), 201
+
+@posts_bp.route('', methods=['GET'])
+def list_posts():
+ posts = Post.query.filter_by(status='published').all()
+ return jsonify([{
+ 'id': p.id,
+ 'title': p.title,
+ 'heat': p.heat,
+ 'created_at': p.created_at.isoformat()
+ } for p in posts])
+
+@posts_bp.route('/<int:post_id>', methods=['GET'])
+def get_post(post_id):
+ post = Post.query.get_or_404(post_id)
+ return jsonify({
+ 'id': post.id,
+ 'user_id': post.user_id,
+ 'title': post.title,
+ 'content': post.content,
+ 'media_urls': post.media_urls,
+ 'status': post.status,
+ 'heat': post.heat,
+ 'created_at': post.created_at.isoformat(),
+ 'updated_at': post.updated_at.isoformat()
+ })
+
+@posts_bp.route('/<int:post_id>', methods=['PUT'])
+def update_post(post_id):
+ """
+ 修改帖子
+ URL 参数:
+ post_id - 要修改的帖子 ID
+ JSON Body 可选字段:
+ title (string)
+ content (string)
+ topic_id (int) — 必须是 topics 表中已有的 ID
+ media_urls (list) — 字符串数组
+ status (string) — 'draft','pending','published','deleted','rejected'
+ """
+ post = Post.query.get_or_404(post_id)
+ data = request.get_json() or {}
+ # 只更新客户端传来的字段
+ for key in ('title','content','topic_id','media_urls','status'):
+ if key in data:
+ setattr(post, key, data[key])
+ db.session.commit()
+ return '', 204
+
+@posts_bp.route('/<int:post_id>', methods=['DELETE'])
+def delete_post(post_id):
+ post = Post.query.get_or_404(post_id)
+ db.session.delete(post)
+ db.session.commit()
+ return '', 204
+
+
+@posts_bp.route('/<int:post_id>/<action>', methods=['POST'])
+def post_action(post_id, action):
+ """
+ 支持的 action: like, favorite, view, share
+ 对于 like 和 favorite,保证每个用户每帖只做一次。
+ """
+ if action not in ('like', 'favorite', 'view', 'share'):
+ abort(400, 'Invalid action')
+
+ data = request.get_json() or {}
+ user_id = data.get('user_id')
+ if not user_id:
+ abort(400, 'user_id required')
+
+ # 对 like/favorite 做去重检查
+ if action in ('like', 'favorite'):
+ exists = Behavior.query.filter_by(
+ user_id=user_id,
+ post_id=post_id,
+ type=action
+ ).first()
+ if exists:
+ return jsonify({'error': f'already {action}d'}), 400
+
+ # 创建行为记录
+ beh = Behavior(user_id=user_id, post_id=post_id, type=action)
+ db.session.add(beh)
+
+ # 更新热度
+ post = Post.query.get_or_404(post_id)
+ post.heat += 1
+
+ db.session.commit()
+ return '', 201
+
+
+# 取消点赞
+@posts_bp.route('/<int:post_id>/like', methods=['DELETE'])
+def unlike(post_id):
+ user_id = request.get_json(silent=True) and request.get_json().get('user_id')
+ if not user_id:
+ abort(400, 'user_id required')
+ # 查找已有的 like 行为
+ beh = Behavior.query.filter_by(
+ user_id=user_id,
+ post_id=post_id,
+ type='like'
+ ).first()
+ if not beh:
+ return jsonify({'error': 'not liked yet'}), 400
+
+ db.session.delete(beh)
+ # 更新热度,确保不降到负数
+ post = Post.query.get_or_404(post_id)
+ post.heat = max(post.heat - 1, 0)
+ db.session.commit()
+ return '', 204
+
+# 取消收藏
+@posts_bp.route('/<int:post_id>/favorite', methods=['DELETE'])
+def unfavorite(post_id):
+ user_id = request.get_json(silent=True) and request.get_json().get('user_id')
+ if not user_id:
+ abort(400, 'user_id required')
+ # 查找已有的 favorite 行为
+ beh = Behavior.query.filter_by(
+ user_id=user_id,
+ post_id=post_id,
+ type='favorite'
+ ).first()
+ if not beh:
+ return jsonify({'error': 'not favorited yet'}), 400
+
+ db.session.delete(beh)
+ # 更新热度
+ post = Post.query.get_or_404(post_id)
+ post.heat = max(post.heat - 1, 0)
+ db.session.commit()
+ return '', 204
\ No newline at end of file