TRM-coding | d1cbf67 | 2025-06-18 15:15:08 +0800 | [diff] [blame] | 1 | # routes/posts.py |
wu | 90da17b | 2025-06-19 12:45:29 +0800 | [diff] [blame] | 2 | |
TRM-coding | d1cbf67 | 2025-06-18 15:15:08 +0800 | [diff] [blame] | 3 | from flask import Blueprint, request, jsonify, abort |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 4 | from extensions import db |
| 5 | from models.post import Post |
TRM-coding | d1cbf67 | 2025-06-18 15:15:08 +0800 | [diff] [blame] | 6 | from models.behavior import Behavior |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 7 | from utils.Fpost import Fpost |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 8 | from sqlalchemy import create_engine |
| 9 | from sqlalchemy.orm import sessionmaker |
| 10 | from config import Config |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 11 | import json |
TRM-coding | d1cbf67 | 2025-06-18 15:15:08 +0800 | [diff] [blame] | 12 | |
| 13 | posts_bp = Blueprint('posts', __name__) |
| 14 | |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 15 | def safe_log(user_id, log_type, message, ip): |
| 16 | user_id=1 |
| 17 | """安全的日志记录函数,不会影响主业务逻辑""" |
| 18 | try: |
| 19 | engine = create_engine(Config.SQLURL) |
| 20 | SessionLocal = sessionmaker(bind=engine) |
| 21 | session = SessionLocal() |
| 22 | f = Fpost(session) |
| 23 | f.recordlog(user_id, log_type, message, ip) |
| 24 | except Exception as e: |
| 25 | # 方法一:简单打印错误信息 |
| 26 | print(f"[safe_log] 记录日志失败:{e}") |
| 27 | traceback.print_exc() # 打印完整的堆栈跟踪 |
| 28 | |
| 29 | # 方法二:使用 logging 模块(推荐) |
| 30 | logger.exception("safe_log: 记录日志时发生异常") |
| 31 | finally: |
| 32 | # 确保 session 一定关闭 |
| 33 | try: |
| 34 | session.close() |
| 35 | except Exception: |
| 36 | pass |
| 37 | |
TRM-coding | d1cbf67 | 2025-06-18 15:15:08 +0800 | [diff] [blame] | 38 | @posts_bp.route('', methods=['POST']) |
| 39 | def create_post(): |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 40 | user_id = None |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 41 | try: |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 42 | # 获取文本字段 |
| 43 | user_id = request.form.get('user_id') |
| 44 | title = request.form.get('title') |
| 45 | content = request.form.get('content') |
| 46 | status = request.form.get('status', 'published') |
| 47 | topic_id = request.form.get('topic_id') |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 48 | media_count = int(request.form.get('media_count', 0)) |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 49 | |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 50 | if not user_id or not title or not content: |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 51 | safe_log(int(user_id) if user_id else 0, 'error', '创建帖子失败:缺少必要字段', request.remote_addr) |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 52 | return jsonify({'error': '缺少必要字段'}), 400 |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 53 | |
| 54 | # 获取上传的文件 |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 55 | files = [] |
| 56 | for i in range(media_count): |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 57 | file_key = f'media_{i}' |
| 58 | if file_key in request.files: |
| 59 | files.append(request.files[file_key]) |
| 60 | |
| 61 | # 使用 Fpost 创建帖子 |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 62 | fpost = Fpost(db.session) |
| 63 | new_post = fpost.create_post_with_files( |
| 64 | user_id=int(user_id), |
| 65 | title=title, |
| 66 | content=content, |
| 67 | topic_id=int(topic_id) if topic_id else None, |
| 68 | status=status, |
| 69 | files=files |
| 70 | ) |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 71 | |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 72 | safe_log(int(user_id), 'behavior', f'成功创建帖子,帖子ID: {new_post.id},标题: {title}', request.remote_addr) |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 73 | return jsonify({'id': new_post.id}), 201 |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 74 | |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 75 | except Exception as e: |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 76 | safe_log(int(user_id) if user_id else 0, 'error', f'创建帖子时发生异常: {str(e)}', request.remote_addr) |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 77 | return jsonify({'error': str(e)}), 500 |
TRM-coding | d1cbf67 | 2025-06-18 15:15:08 +0800 | [diff] [blame] | 78 | |
| 79 | @posts_bp.route('', methods=['GET']) |
| 80 | def list_posts(): |
wu | 90da17b | 2025-06-19 12:45:29 +0800 | [diff] [blame] | 81 | """ |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 82 | 获取帖子列表,支持: |
| 83 | - GET /posts 返回所有已发布帖子 |
| 84 | - GET /posts?user_id=123 返回指定用户 user_id 的所有帖子 |
wu | 90da17b | 2025-06-19 12:45:29 +0800 | [diff] [blame] | 85 | """ |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 86 | user_id = None |
| 87 | try: |
| 88 | user_id = request.args.get('user_id', type=int) |
| 89 | query = Post.query |
| 90 | if user_id is not None: |
| 91 | query = query.filter_by(user_id=user_id) |
| 92 | else: |
| 93 | query = query.filter_by(status='published') |
wu | 90da17b | 2025-06-19 12:45:29 +0800 | [diff] [blame] | 94 | |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 95 | posts = query.all() |
| 96 | |
| 97 | log_msg = f'获取帖子列表成功,共{len(posts)}个帖子' |
| 98 | if user_id: |
| 99 | log_msg += f',用户ID: {user_id}' |
| 100 | safe_log(user_id if user_id else 0, 'access', log_msg, request.remote_addr) |
TRM-coding | d1cbf67 | 2025-06-18 15:15:08 +0800 | [diff] [blame] | 101 | |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 102 | return jsonify([{ |
| 103 | 'id': p.id, |
| 104 | 'title': p.title, |
| 105 | 'status': p.status, |
| 106 | 'heat': p.heat, |
| 107 | 'created_at': p.created_at.isoformat() |
| 108 | } for p in posts]) |
| 109 | |
| 110 | except Exception as e: |
| 111 | safe_log(user_id if user_id else 0, 'error', f'获取帖子列表时发生异常: {str(e)}', request.remote_addr) |
| 112 | return jsonify({'error': str(e)}), 500 |
wu | 5a4acf7 | 2025-06-24 15:38:29 +0800 | [diff] [blame] | 113 | |
TRM-coding | d1cbf67 | 2025-06-18 15:15:08 +0800 | [diff] [blame] | 114 | @posts_bp.route('/<int:post_id>', methods=['GET']) |
| 115 | def get_post(post_id): |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 116 | try: |
| 117 | post = Post.query.get_or_404(post_id) |
| 118 | safe_log(0, 'access', f'获取帖子详情成功,帖子ID: {post_id},标题: {post.title}', request.remote_addr) |
| 119 | |
| 120 | return jsonify({ |
| 121 | 'id': post.id, |
| 122 | 'user_id': post.user_id, |
| 123 | 'topic_id': post.topic_id, |
| 124 | 'title': post.title, |
| 125 | 'content': post.content, |
| 126 | 'media_urls': post.media_urls, |
| 127 | 'status': post.status, |
| 128 | 'heat': post.heat, |
| 129 | 'created_at': post.created_at.isoformat(), |
| 130 | 'updated_at': post.updated_at.isoformat() |
| 131 | }) |
| 132 | |
| 133 | except Exception as e: |
| 134 | safe_log(0, 'error', f'获取帖子详情时发生异常,帖子ID: {post_id},错误: {str(e)}', request.remote_addr) |
| 135 | return jsonify({'error': str(e)}), 500 |
TRM-coding | d1cbf67 | 2025-06-18 15:15:08 +0800 | [diff] [blame] | 136 | |
| 137 | @posts_bp.route('/<int:post_id>', methods=['PUT']) |
| 138 | def update_post(post_id): |
| 139 | """ |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 140 | 修改帖子字段(可选字段:title, content, topic_id, media_urls, status) |
| 141 | 支持FormData和JSON两种格式 |
TRM-coding | d1cbf67 | 2025-06-18 15:15:08 +0800 | [diff] [blame] | 142 | """ |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 143 | try: |
| 144 | fpost = Fpost(db.session) |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 145 | |
| 146 | # 检查是否是FormData请求 |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 147 | if request.content_type and 'multipart/form-data' in request.content_type: |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 148 | # FormData请求 |
| 149 | title = request.form.get('title') |
| 150 | content = request.form.get('content') |
| 151 | status = request.form.get('status') |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 152 | topic_id = request.form.get('topic_id') |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 153 | media_count = int(request.form.get('media_count', 0)) |
| 154 | existing_media_urls_str = request.form.get('existing_media_urls') |
| 155 | |
| 156 | # 解析现有媒体URLs |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 157 | existing_media_urls = None |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 158 | if existing_media_urls_str: |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 159 | try: |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 160 | existing_media_urls = json.loads(existing_media_urls_str) |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 161 | except: |
| 162 | existing_media_urls = None |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 163 | |
| 164 | # 获取新上传的文件 |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 165 | files = [] |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 166 | for i in range(media_count): |
| 167 | file_key = f'media_{i}' |
| 168 | if file_key in request.files: |
| 169 | files.append(request.files[file_key]) |
| 170 | |
| 171 | # 更新帖子 |
| 172 | updated_post = fpost.update_post_with_files( |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 173 | post_id=post_id, |
| 174 | title=title, |
| 175 | content=content, |
| 176 | topic_id=int(topic_id) if topic_id else None, |
| 177 | status=status, |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 178 | files=files if files else None, |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 179 | existing_media_urls=existing_media_urls |
| 180 | ) |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 181 | |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 182 | else: |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 183 | # JSON请求(保持原有逻辑) |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 184 | post = Post.query.get_or_404(post_id) |
| 185 | data = request.get_json() or {} |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 186 | for key in ('title', 'content', 'topic_id', 'media_urls', 'status'): |
| 187 | if key in data: |
| 188 | setattr(post, key, data[key]) |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 189 | db.session.commit() |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 190 | updated_post = post |
| 191 | |
| 192 | if not updated_post: |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 193 | safe_log(0, 'error', f'更新帖子失败,帖子不存在,帖子ID: {post_id}', request.remote_addr) |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 194 | return jsonify({'error': '帖子不存在'}), 404 |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 195 | |
| 196 | safe_log(0, 'behavior', f'更新帖子成功,帖子ID: {post_id}', request.remote_addr) |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 197 | return '', 204 |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 198 | |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 199 | except Exception as e: |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 200 | safe_log(0, 'error', f'更新帖子时发生异常,帖子ID: {post_id},错误: {str(e)}', request.remote_addr) |
TRM-coding | f55d237 | 2025-06-20 16:22:37 +0800 | [diff] [blame] | 201 | return jsonify({'error': str(e)}), 500 |
TRM-coding | d1cbf67 | 2025-06-18 15:15:08 +0800 | [diff] [blame] | 202 | |
| 203 | @posts_bp.route('/<int:post_id>', methods=['DELETE']) |
| 204 | def delete_post(post_id): |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 205 | try: |
| 206 | post = Post.query.get_or_404(post_id) |
| 207 | db.session.delete(post) |
| 208 | db.session.commit() |
| 209 | safe_log(0, 'behavior', f'删除帖子成功,帖子ID: {post_id}', request.remote_addr) |
| 210 | return '', 204 |
| 211 | |
| 212 | except Exception as e: |
| 213 | safe_log(0, 'error', f'删除帖子时发生异常,帖子ID: {post_id},错误: {str(e)}', request.remote_addr) |
| 214 | return jsonify({'error': str(e)}), 500 |
TRM-coding | d1cbf67 | 2025-06-18 15:15:08 +0800 | [diff] [blame] | 215 | |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 216 | @posts_bp.route('/<int:post_id>/<action>', methods=['POST']) |
| 217 | def post_action(post_id, action): |
| 218 | """ |
| 219 | 支持的 action: like, favorite, view, share |
| 220 | 对于 like 和 favorite,保证每个用户每帖只做一次。 |
| 221 | """ |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 222 | user_id = None |
| 223 | try: |
| 224 | if action not in ('like', 'favorite', 'view', 'share'): |
| 225 | abort(400, 'Invalid action') |
TRM-coding | d1cbf67 | 2025-06-18 15:15:08 +0800 | [diff] [blame] | 226 | |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 227 | data = request.get_json() or {} |
| 228 | user_id = data.get('user_id') |
| 229 | if not user_id: |
| 230 | safe_log(0, 'error', f'执行帖子操作失败,缺少用户ID,帖子ID: {post_id},操作: {action}', request.remote_addr) |
| 231 | abort(400, 'user_id required') |
wu | 5934be4 | 2025-06-24 11:50:34 +0800 | [diff] [blame] | 232 | |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 233 | # 对 like/favorite 做去重检查 |
| 234 | if action in ('like', 'favorite'): |
| 235 | exists = Behavior.query.filter_by( |
| 236 | user_id=user_id, |
| 237 | post_id=post_id, |
| 238 | type=action |
| 239 | ).first() |
| 240 | if exists: |
| 241 | safe_log(user_id, 'error', f'重复执行帖子操作,帖子ID: {post_id},操作: {action}', request.remote_addr) |
| 242 | return jsonify({'error': f'already {action}d'}), 400 |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 243 | |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 244 | # 创建行为记录 |
| 245 | beh = Behavior(user_id=user_id, post_id=post_id, type=action) |
| 246 | db.session.add(beh) |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 247 | |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 248 | # 更新热度 |
| 249 | post = Post.query.get_or_404(post_id) |
| 250 | post.heat += 1 |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 251 | |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 252 | db.session.commit() |
| 253 | safe_log(user_id, 'behavior', f'执行帖子操作成功,帖子ID: {post_id},操作: {action}', request.remote_addr) |
| 254 | return '', 201 |
| 255 | |
| 256 | except Exception as e: |
| 257 | safe_log(user_id if user_id else 0, 'error', f'执行帖子操作时发生异常,帖子ID: {post_id},操作: {action},错误: {str(e)}', request.remote_addr) |
| 258 | return jsonify({'error': str(e)}), 500 |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 259 | |
| 260 | @posts_bp.route('/<int:post_id>/like', methods=['DELETE']) |
| 261 | def unlike(post_id): |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 262 | user_id = None |
| 263 | try: |
| 264 | user_id = request.get_json(silent=True) and request.get_json().get('user_id') |
| 265 | if not user_id: |
| 266 | safe_log(0, 'error', f'取消点赞失败,缺少用户ID,帖子ID: {post_id}', request.remote_addr) |
| 267 | abort(400, 'user_id required') |
| 268 | |
| 269 | # 查找已有的 like 行为 |
| 270 | beh = Behavior.query.filter_by( |
| 271 | user_id=user_id, |
| 272 | post_id=post_id, |
| 273 | type='like' |
| 274 | ).first() |
| 275 | if not beh: |
| 276 | safe_log(user_id, 'error', f'取消点赞失败,用户尚未点赞,帖子ID: {post_id}', request.remote_addr) |
| 277 | return jsonify({'error': 'not liked yet'}), 400 |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 278 | |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 279 | db.session.delete(beh) |
| 280 | # 更新热度,确保不降到负数 |
| 281 | post = Post.query.get_or_404(post_id) |
| 282 | post.heat = max(post.heat - 1, 0) |
| 283 | db.session.commit() |
| 284 | safe_log(user_id, 'behavior', f'取消点赞成功,帖子ID: {post_id}', request.remote_addr) |
| 285 | return '', 204 |
| 286 | |
| 287 | except Exception as e: |
| 288 | safe_log(user_id if user_id else 0, 'error', f'取消点赞时发生异常,帖子ID: {post_id},错误: {str(e)}', request.remote_addr) |
| 289 | return jsonify({'error': str(e)}), 500 |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 290 | |
| 291 | @posts_bp.route('/<int:post_id>/favorite', methods=['DELETE']) |
| 292 | def unfavorite(post_id): |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 293 | user_id = None |
| 294 | try: |
| 295 | user_id = request.get_json(silent=True) and request.get_json().get('user_id') |
| 296 | if not user_id: |
| 297 | safe_log(0, 'error', f'取消收藏失败,缺少用户ID,帖子ID: {post_id}', request.remote_addr) |
| 298 | abort(400, 'user_id required') |
| 299 | |
| 300 | # 查找已有的 favorite 行为 |
| 301 | beh = Behavior.query.filter_by( |
| 302 | user_id=user_id, |
| 303 | post_id=post_id, |
| 304 | type='favorite' |
| 305 | ).first() |
| 306 | if not beh: |
| 307 | safe_log(user_id, 'error', f'取消收藏失败,用户尚未收藏,帖子ID: {post_id}', request.remote_addr) |
| 308 | return jsonify({'error': 'not favorited yet'}), 400 |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 309 | |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 310 | db.session.delete(beh) |
| 311 | # 更新热度 |
| 312 | post = Post.query.get_or_404(post_id) |
| 313 | post.heat = max(post.heat - 1, 0) |
| 314 | db.session.commit() |
| 315 | safe_log(user_id, 'behavior', f'取消收藏成功,帖子ID: {post_id}', request.remote_addr) |
| 316 | return '', 204 |
| 317 | |
| 318 | except Exception as e: |
| 319 | safe_log(user_id if user_id else 0, 'error', f'取消收藏时发生异常,帖子ID: {post_id},错误: {str(e)}', request.remote_addr) |
| 320 | return jsonify({'error': str(e)}), 500 |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 321 | |
| 322 | @posts_bp.route('/<int:post_id>/like/status', methods=['GET']) |
wu | 5934be4 | 2025-06-24 11:50:34 +0800 | [diff] [blame] | 323 | def has_liked(post_id): |
| 324 | """ |
wu | 5249153 | 2025-06-24 22:47:35 +0800 | [diff] [blame] | 325 | 检查指定 user_id 是否对 post_id 点过赞。 |
| 326 | GET /posts/<post_id>/like/status?user_id=123 |
| 327 | 返回 { "liked": true } 或 { "liked": false } |
wu | 5934be4 | 2025-06-24 11:50:34 +0800 | [diff] [blame] | 328 | """ |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 329 | user_id = None |
| 330 | try: |
| 331 | user_id = request.args.get('user_id', type=int) |
| 332 | if not user_id: |
| 333 | safe_log(0, 'error', f'检查点赞状态失败,缺少用户ID,帖子ID: {post_id}', request.remote_addr) |
| 334 | abort(400, 'user_id required') |
wu | 5934be4 | 2025-06-24 11:50:34 +0800 | [diff] [blame] | 335 | |
trm | faf2af5 | 2025-06-27 17:05:44 +0000 | [diff] [blame^] | 336 | exists = Behavior.query.filter_by( |
| 337 | user_id=user_id, |
| 338 | post_id=post_id, |
| 339 | type='like' |
| 340 | ).first() is not None |
| 341 | |
| 342 | safe_log(user_id, 'access', f'检查点赞状态成功,帖子ID: {post_id},结果: {exists}', request.remote_addr) |
| 343 | return jsonify({'liked': exists}), 200 |
| 344 | |
| 345 | except Exception as e: |
| 346 | safe_log(user_id if user_id else 0, 'error', f'检查点赞状态时发生异常,帖子ID: {post_id},错误: {str(e)}', request.remote_addr) |
| 347 | return jsonify({'error': str(e)}), 500 |