blob: d4994c1c5e7b65c6c86869413b7db80dc583a290 [file] [log] [blame]
wueb6e6ca2025-06-15 10:35:32 +08001# routes/posts.py
wu90da17b2025-06-19 12:45:29 +08002
wueb6e6ca2025-06-15 10:35:32 +08003from flask import Blueprint, request, jsonify, abort
wu5a4acf72025-06-24 15:38:29 +08004from extensions import db
5from models.post import Post
wueb6e6ca2025-06-15 10:35:32 +08006from models.behavior import Behavior
7
8posts_bp = Blueprint('posts', __name__)
9
10@posts_bp.route('', methods=['POST'])
11def create_post():
wu5a4acf72025-06-24 15:38:29 +080012 """
13 POST /posts
14 接收 application/json 格式:
15 { "user_id": ..., "title": ..., "content": ..., "topic_id": ..., "media_urls": [...], "status": ... }
16 """
wueb6e6ca2025-06-15 10:35:32 +080017 data = request.get_json() or {}
18 post = Post(**data)
19 db.session.add(post)
20 db.session.commit()
21 return jsonify({'id': post.id}), 201
22
wu5a4acf72025-06-24 15:38:29 +080023
wueb6e6ca2025-06-15 10:35:32 +080024@posts_bp.route('', methods=['GET'])
25def list_posts():
wu90da17b2025-06-19 12:45:29 +080026 """
wu5a4acf72025-06-24 15:38:29 +080027 GET /posts → 返回所有已发布帖子
28 GET /posts?user_id=xx → 返回指定用户的所有帖子
wu90da17b2025-06-19 12:45:29 +080029 """
30 user_id = request.args.get('user_id', type=int)
31 query = Post.query
32 if user_id is not None:
33 query = query.filter_by(user_id=user_id)
34 else:
35 query = query.filter_by(status='published')
wu90da17b2025-06-19 12:45:29 +080036
wu5a4acf72025-06-24 15:38:29 +080037 posts = query.all()
wueb6e6ca2025-06-15 10:35:32 +080038 return jsonify([{
wu5a4acf72025-06-24 15:38:29 +080039 'id' : p.id,
40 'title' : p.title,
41 'status' : p.status,
42 'heat' : p.heat,
43 'created_at' : p.created_at.isoformat()
wueb6e6ca2025-06-15 10:35:32 +080044 } for p in posts])
45
wu5a4acf72025-06-24 15:38:29 +080046
wueb6e6ca2025-06-15 10:35:32 +080047@posts_bp.route('/<int:post_id>', methods=['GET'])
48def get_post(post_id):
wu5a4acf72025-06-24 15:38:29 +080049 """
50 GET /posts/<post_id>
51 """
wueb6e6ca2025-06-15 10:35:32 +080052 post = Post.query.get_or_404(post_id)
53 return jsonify({
wu5a4acf72025-06-24 15:38:29 +080054 'id' : post.id,
55 'user_id' : post.user_id,
56 'topic_id' : post.topic_id,
57 'title' : post.title,
58 'content' : post.content,
59 'media_urls' : post.media_urls,
60 'status' : post.status,
61 'heat' : post.heat,
62 'created_at' : post.created_at.isoformat(),
63 'updated_at' : post.updated_at.isoformat()
wueb6e6ca2025-06-15 10:35:32 +080064 })
65
wu5a4acf72025-06-24 15:38:29 +080066
wueb6e6ca2025-06-15 10:35:32 +080067@posts_bp.route('/<int:post_id>', methods=['PUT'])
68def update_post(post_id):
69 """
wu5a4acf72025-06-24 15:38:29 +080070 PUT /posts/<post_id>
71 接收 application/json 格式,可选字段:
72 title, content, topic_id, media_urls, status
wueb6e6ca2025-06-15 10:35:32 +080073 """
74 post = Post.query.get_or_404(post_id)
75 data = request.get_json() or {}
wu90da17b2025-06-19 12:45:29 +080076 for key in ('title', 'content', 'topic_id', 'media_urls', 'status'):
wueb6e6ca2025-06-15 10:35:32 +080077 if key in data:
78 setattr(post, key, data[key])
79 db.session.commit()
80 return '', 204
81
wu5a4acf72025-06-24 15:38:29 +080082
wueb6e6ca2025-06-15 10:35:32 +080083@posts_bp.route('/<int:post_id>', methods=['DELETE'])
84def delete_post(post_id):
wu5a4acf72025-06-24 15:38:29 +080085 """
86 DELETE /posts/<post_id>
87 """
wueb6e6ca2025-06-15 10:35:32 +080088 post = Post.query.get_or_404(post_id)
89 db.session.delete(post)
90 db.session.commit()
91 return '', 204
92
wueb6e6ca2025-06-15 10:35:32 +080093
wu5a4acf72025-06-24 15:38:29 +080094@posts_bp.route('/<int:post_id>/like', methods=['GET'])
95def has_liked(post_id):
96 """
97 GET /posts/<post_id>/like?user_id=xx
98 返回 { "liked": true/false }
99 """
100 user_id = request.args.get('user_id', type=int)
101 if not user_id:
102 abort(400, 'user_id required')
103
104 exists = Behavior.query.filter_by(
105 user_id=user_id,
106 post_id=post_id,
107 type='like'
108 ).first() is not None
109
110 return jsonify({'liked': exists}), 200
111
112
113@posts_bp.route('/<int:post_id>/like', methods=['DELETE'])
114def unlike(post_id):
115 """
116 DELETE /posts/<post_id>/like
117 body: { "user_id": xx }
118 """
119 data = request.get_json(silent=True) or {}
wueb6e6ca2025-06-15 10:35:32 +0800120 user_id = data.get('user_id')
121 if not user_id:
122 abort(400, 'user_id required')
123
wu5a4acf72025-06-24 15:38:29 +0800124 beh = Behavior.query.filter_by(
125 user_id=user_id,
126 post_id=post_id,
127 type='like'
128 ).first()
129 if not beh:
130 return jsonify({'error': 'not liked yet'}), 400
131
132 db.session.delete(beh)
133 post = Post.query.get_or_404(post_id)
134 post.heat = max(post.heat - 1, 0)
135 db.session.commit()
136 return '', 204
137
138
139@posts_bp.route('/<int:post_id>/favorite', methods=['DELETE'])
140def unfavorite(post_id):
141 """
142 DELETE /posts/<post_id>/favorite
143 body: { "user_id": xx }
144 """
145 data = request.get_json(silent=True) or {}
146 user_id = data.get('user_id')
147 if not user_id:
148 abort(400, 'user_id required')
149
150 beh = Behavior.query.filter_by(
151 user_id=user_id,
152 post_id=post_id,
153 type='favorite'
154 ).first()
155 if not beh:
156 return jsonify({'error': 'not favorited yet'}), 400
157
158 db.session.delete(beh)
159 post = Post.query.get_or_404(post_id)
160 post.heat = max(post.heat - 1, 0)
161 db.session.commit()
162 return '', 204
163
164
165@posts_bp.route('/<int:post_id>/<action>', methods=['POST'])
166def post_action(post_id, action):
167 """
168 POST /posts/<post_id>/<action>
169 支持 action: like, favorite, view, share
170 """
171 if action not in ('like', 'favorite', 'view', 'share'):
172 abort(400, 'Invalid action')
173
174 data = request.get_json() or {}
175 user_id = data.get('user_id')
176 if not user_id:
177 abort(400, 'user_id required')
178
179 # 幂等检查
wueb6e6ca2025-06-15 10:35:32 +0800180 if action in ('like', 'favorite'):
181 exists = Behavior.query.filter_by(
182 user_id=user_id,
183 post_id=post_id,
184 type=action
185 ).first()
186 if exists:
187 return jsonify({'error': f'already {action}d'}), 400
188
189 # 创建行为记录
190 beh = Behavior(user_id=user_id, post_id=post_id, type=action)
191 db.session.add(beh)
192
193 # 更新热度
194 post = Post.query.get_or_404(post_id)
195 post.heat += 1
196
197 db.session.commit()
198 return '', 201