personal page
Change-Id: I893fc586bd501f1067844ca4812be740aa8ed4ec
diff --git a/xiaohongshu-upload-platform/src/ljc/back_end/app.py b/xiaohongshu-upload-platform/src/ljc/back_end/app.py
new file mode 100644
index 0000000..cb62a4d
--- /dev/null
+++ b/xiaohongshu-upload-platform/src/ljc/back_end/app.py
@@ -0,0 +1,460 @@
+from flask import Flask, jsonify, request, session
+from flask_sqlalchemy import SQLAlchemy
+from flask_cors import CORS
+
+app = Flask(__name__)
+app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456@10.126.59.25/redbook'
+app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
+app.secret_key = 'your_secret_key'
+CORS(app, supports_credentials=True)
+
+db = SQLAlchemy(app)
+
+# 模型定义
+# 用户表
+class User(db.Model):
+ __tablename__ = 'users'
+ id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment='用户ID')
+ username = db.Column(db.String(50), unique=True, nullable=False, comment='用户名')
+ password = db.Column(db.String(255), nullable=False, comment='加密密码')
+ email = db.Column(db.String(100), unique=True, nullable=False, comment='邮箱')
+ avatar = db.Column(db.String(255), comment='头像URL')
+ role = db.Column(db.Enum('superadmin', 'user', 'admin'), default='user', comment='角色')
+ bio = db.Column(db.String(255), comment='个人简介')
+ status = db.Column(db.Enum('active', 'banned', 'muted'), default='active', comment='账号状态')
+ created_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), comment='创建时间')
+ updated_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(),
+ onupdate=db.func.current_timestamp(), comment='更新时间')
+
+ # 关系定义
+ posts = db.relationship('Post', backref='author', lazy=True)
+ behaviors = db.relationship('Behavior', backref='user', lazy=True)
+ comments = db.relationship('Comment', backref='commenter', lazy=True)
+ notifications = db.relationship('Notification', backref='recipient', lazy=True)
+ audits = db.relationship('Audit', backref='admin', lazy=True)
+ logs = db.relationship('Log', backref='logger', lazy=True)
+ user_tags = db.relationship('UserTag', backref='user', lazy=True)
+
+# 标签表
+class Tag(db.Model):
+ __tablename__ = 'tags'
+ id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment='标签ID')
+ name = db.Column(db.String(50), unique=True, nullable=False, comment='标签名称')
+ description = db.Column(db.String(255), comment='标签描述')
+ created_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), comment='创建时间')
+
+ # 关系定义
+ post_tags = db.relationship('PostTag', backref='tag', lazy=True)
+ user_tags = db.relationship('UserTag', backref='tag', lazy=True)
+
+# 话题/超话表
+class Topic(db.Model):
+ __tablename__ = 'topics'
+ id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment='话题ID')
+ name = db.Column(db.String(100), unique=True, nullable=False, comment='话题名称')
+ description = db.Column(db.Text, comment='话题描述')
+ status = db.Column(db.Enum('active', 'archived'), default='active', comment='状态')
+ created_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), comment='创建时间')
+
+ # 关系定义
+ posts = db.relationship('Post', backref='topic', lazy=True)
+
+# 内容帖子表
+class Post(db.Model):
+ __tablename__ = 'posts'
+ id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment='帖子ID')
+ user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), nullable=False, comment='作者ID')
+ topic_id = db.Column(db.Integer, db.ForeignKey('topics.id', ondelete='SET NULL'), comment='所属话题ID')
+ type = db.Column(db.Enum('text', 'image', 'video', 'document'), default='text', comment='内容类型')
+ title = db.Column(db.String(255), nullable=False, comment='标题')
+ content = db.Column(db.Text, nullable=False, comment='正文内容')
+ media_urls = db.Column(db.JSON, comment='媒体资源URL数组')
+ status = db.Column(db.Enum('draft', 'pending', 'published', 'deleted', 'rejected'), default='draft', comment='状态')
+ heat = db.Column(db.Integer, default=0, comment='热度值')
+ created_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), comment='创建时间')
+ updated_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(),
+ onupdate=db.func.current_timestamp(), comment='更新时间')
+
+ # 关系定义
+ behaviors = db.relationship('Behavior', backref='post', lazy=True)
+ comments = db.relationship('Comment', backref='post', lazy=True)
+ post_tags = db.relationship('PostTag', backref='post', lazy=True)
+ audits = db.relationship('Audit', backref='post', lazy=True)
+
+# 帖子标签关联表
+class PostTag(db.Model):
+ __tablename__ = 'post_tags'
+ post_id = db.Column(db.Integer, db.ForeignKey('posts.id', ondelete='CASCADE'), primary_key=True, comment='帖子ID')
+ tag_id = db.Column(db.Integer, db.ForeignKey('tags.id', ondelete='CASCADE'), primary_key=True, comment='标签ID')
+
+# 用户行为表
+class Behavior(db.Model):
+ __tablename__ = 'behaviors'
+ id = db.Column(db.BigInteger, primary_key=True, autoincrement=True, comment='行为ID')
+ user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), nullable=False, comment='用户ID')
+ post_id = db.Column(db.Integer, db.ForeignKey('posts.id', ondelete='CASCADE'), nullable=False, comment='帖子ID')
+ type = db.Column(db.Enum('like', 'comment', 'favorite', 'view', 'share'), nullable=False, comment='行为类型')
+ value = db.Column(db.Integer, default=1, comment='行为值')
+ created_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), comment='行为时间')
+
+# 评论表
+class Comment(db.Model):
+ __tablename__ = 'comments'
+ id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment='评论ID')
+ post_id = db.Column(db.Integer, db.ForeignKey('posts.id', ondelete='CASCADE'), nullable=False, comment='帖子ID')
+ user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), nullable=False, comment='用户ID')
+ parent_id = db.Column(db.Integer, db.ForeignKey('comments.id', ondelete='CASCADE'), comment='父评论ID')
+ content = db.Column(db.Text, nullable=False, comment='评论内容')
+ status = db.Column(db.Enum('active', 'deleted'), default='active', comment='状态')
+ created_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), comment='创建时间')
+ updated_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(),
+ onupdate=db.func.current_timestamp(), comment='更新时间')
+
+ # 关系定义
+ replies = db.relationship('Comment', backref=db.backref('parent', remote_side=[id]), lazy=True)
+
+# 用户关注关系表
+class Follow(db.Model):
+ __tablename__ = 'follows'
+ follower_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), primary_key=True, comment='关注者ID')
+ followee_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), primary_key=True, comment='被关注者ID')
+ created_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), comment='关注时间')
+
+ # 关系定义
+ follower = db.relationship('User', foreign_keys=[follower_id], backref='following')
+ followee = db.relationship('User', foreign_keys=[followee_id], backref='followers')
+
+# 通知表
+class Notification(db.Model):
+ __tablename__ = 'notifications'
+ id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment='通知ID')
+ user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), nullable=False, comment='接收用户ID')
+ type = db.Column(db.Enum('like', 'comment', 'follow', 'system', 'audit'), nullable=False, comment='通知类型')
+ content = db.Column(db.JSON, nullable=False, comment='通知内容')
+ is_read = db.Column(db.Boolean, default=False, comment='是否已读')
+ created_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), comment='创建时间')
+
+# 审核记录表
+class Audit(db.Model):
+ __tablename__ = 'audits'
+ id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment='审核ID')
+ post_id = db.Column(db.Integer, db.ForeignKey('posts.id', ondelete='CASCADE'), nullable=False, comment='帖子ID')
+ admin_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), nullable=False, comment='管理员ID')
+ result = db.Column(db.Enum('approved', 'rejected'), nullable=False, comment='审核结果')
+ reason = db.Column(db.String(255), comment='审核原因')
+ created_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), comment='审核时间')
+
+# 日志表
+class Log(db.Model):
+ __tablename__ = 'logs'
+ id = db.Column(db.BigInteger, primary_key=True, autoincrement=True, comment='日志ID')
+ user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='SET NULL'), comment='用户ID')
+ type = db.Column(db.Enum('access', 'error', 'behavior', 'system'), nullable=False, comment='日志类型')
+ content = db.Column(db.Text, nullable=False, comment='日志内容')
+ ip = db.Column(db.String(45), comment='IP地址')
+ created_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), comment='记录时间')
+
+# 用户兴趣标签表
+class UserTag(db.Model):
+ __tablename__ = 'user_tags'
+ user_id = db.Column(db.Integer, db.ForeignKey('users.id', ondelete='CASCADE'), primary_key=True, comment='用户ID')
+ tag_id = db.Column(db.Integer, db.ForeignKey('tags.id', ondelete='CASCADE'), primary_key=True, comment='标签ID')
+ weight = db.Column(db.Float, default=1.0, comment='兴趣权重')
+ created_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(), comment='创建时间')
+ updated_at = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(),
+ onupdate=db.func.current_timestamp(), comment='更新时间')
+
+
+# 自动登录用户11
+@app.before_request
+def auto_login():
+ # 如果用户未登录,自动设置为用户11
+ if 'user_id' not in session:
+ session['user_id'] = 11
+
+# 获取当前用户信息
+@app.route('/api/current-user')
+def current_user():
+ user_id = session.get('user_id', 1)
+ user = User.query.get(user_id)
+ if not user:
+ return jsonify({'error': 'User not found'}), 404
+
+ following_count = Follow.query.filter_by(follower_id=user_id).count()
+ followers_count = Follow.query.filter_by(followee_id=user_id).count()
+
+ return jsonify({
+ 'id': user.id,
+ 'username': user.username,
+ 'email': user.email,
+ 'avatar': user.avatar,
+ 'bio': user.bio,
+ 'following_count': following_count,
+ 'followers_count': followers_count
+ })
+
+# 获取指定用户信息
+@app.route('/api/user/<int:user_id>')
+def get_user(user_id):
+ current_user_id = session.get('user_id', 1)
+ user = User.query.get(user_id)
+ if not user:
+ return jsonify({'error': 'User not found'}), 404
+
+ following_count = Follow.query.filter_by(follower_id=user_id).count()
+ followers_count = Follow.query.filter_by(followee_id=user_id).count()
+
+ is_following = False
+ if current_user_id:
+ is_following = Follow.query.filter_by(
+ follower_id=current_user_id,
+ followee_id=user_id
+ ).first() is not None
+
+ return jsonify({
+ 'id': user.id,
+ 'username': user.username,
+ 'avatar': user.avatar,
+ 'bio': user.bio,
+ 'following_count': following_count,
+ 'followers_count': followers_count,
+ 'is_following': is_following
+ })
+
+# 更新用户信息
+@app.route('/api/user/<int:user_id>', methods=['PUT'])
+def update_user(user_id):
+ current_user_id = session.get('user_id', 1)
+ if current_user_id != user_id:
+ return jsonify({'error': 'Unauthorized'}), 403
+
+ user = User.query.get(user_id)
+ if not user:
+ return jsonify({'error': 'User not found'}), 404
+
+ data = request.json
+ if 'avatar' in data:
+ user.avatar = data['avatar']
+ if 'bio' in data:
+ user.bio = data['bio']
+
+ db.session.commit()
+ return jsonify({
+ 'id': user.id,
+ 'avatar': user.avatar,
+ 'bio': user.bio
+ })
+
+# 获取用户收藏
+@app.route('/api/user/<int:user_id>/favorites', methods=['GET'])
+def get_user_favorites(user_id):
+ # 检查用户是否登录
+ if 'user_id' not in session:
+ return jsonify({'error': '未登录'}), 401
+
+ # 验证请求的用户ID与登录用户ID是否一致
+ if session['user_id'] != user_id:
+ return jsonify({'error': '无权访问其他用户的收藏'}), 403
+
+ try:
+ # 获取收藏行为及其关联的帖子
+ favorites = db.session.query(Behavior, Post).join(
+ Post, Behavior.post_id == Post.id
+ ).filter(
+ Behavior.user_id == user_id,
+ Behavior.type == 'favorite'
+ ).all()
+
+ # 构建响应数据
+ result = []
+ for behavior, post in favorites:
+ # 获取帖子作者信息
+ author = User.query.get(post.user_id)
+
+ # 构建响应对象
+ result.append({
+ 'behavior_id': behavior.id,
+ 'post': {
+ 'id': post.id,
+ 'title': post.title,
+ 'type': post.type,
+ 'content_preview': post.content[:100] + '...' if len(post.content) > 100 else post.content,
+ 'media_urls': post.media_urls,
+ 'created_at': post.created_at.strftime('%Y-%m-%d %H:%M:%S'),
+ 'author': {
+ 'id': author.id,
+ 'username': author.username,
+ 'avatar': author.avatar
+ }
+ },
+ 'favorited_at': behavior.created_at.strftime('%Y-%m-%d %H:%M:%S')
+ })
+
+ return jsonify(result)
+
+ except Exception as e:
+ app.logger.error(f"获取收藏时出错: {str(e)}")
+ return jsonify({'error': '获取收藏失败'}), 500
+
+
+# 获取用户发布的帖子
+@app.route('/api/user/<int:user_id>/posts')
+def get_user_posts(user_id):
+ # 允许任何人查看用户发布的帖子
+ posts = Post.query.filter_by(
+ user_id=user_id,
+ status='published'
+ ).all()
+
+ return jsonify([{
+ 'id': post.id,
+ 'title': post.title,
+ 'content': post.content[:100] + '...' if len(post.content) > 100 else post.content,
+ 'type': post.type,
+ 'heat': post.heat,
+ 'created_at': post.created_at.strftime('%Y-%m-%d %H:%M')
+ } for post in posts])
+
+# 获取用户关注列表
+@app.route('/api/user/<int:user_id>/following')
+def get_user_following(user_id):
+ # 允许任何人查看用户的关注列表
+ following = Follow.query.filter_by(follower_id=user_id).all()
+
+ # 获取被关注用户的详细信息
+ following_list = []
+ for follow in following:
+ user = User.query.get(follow.followee_id)
+ if user:
+ followers_count = Follow.query.filter_by(followee_id=user.id).count()
+
+ following_list.append({
+ 'id': user.id,
+ 'username': user.username,
+ 'avatar': user.avatar,
+ 'followers_count': followers_count
+ })
+
+ return jsonify(following_list)
+
+# 关注/取消关注用户
+@app.route('/api/follow/<int:followee_id>', methods=['POST', 'DELETE'])
+def follow_user(followee_id):
+ follower_id = session.get('user_id', 1)
+ if follower_id == followee_id:
+ return jsonify({'error': 'Cannot follow yourself'}), 400
+
+ if request.method == 'POST':
+ existing = Follow.query.filter_by(
+ follower_id=follower_id,
+ followee_id=followee_id
+ ).first()
+
+ if not existing:
+ follow = Follow(
+ follower_id=follower_id,
+ followee_id=followee_id
+ )
+ db.session.add(follow)
+ db.session.commit()
+ return jsonify({'message': 'Followed successfully'})
+
+ elif request.method == 'DELETE':
+ follow = Follow.query.filter_by(
+ follower_id=follower_id,
+ followee_id=followee_id
+ ).first()
+
+ if follow:
+ db.session.delete(follow)
+ db.session.commit()
+ return jsonify({'message': 'Unfollowed successfully'})
+
+
+# 新增获取粉丝列表的API
+@app.route('/api/user/<int:user_id>/followers')
+def get_user_followers(user_id):
+ try:
+ # 查询关注该用户的用户列表
+ followers = db.session.query(User).join(
+ Follow, Follow.follower_id == User.id
+ ).filter(
+ Follow.followee_id == user_id
+ ).all()
+
+ # 获取当前登录用户ID(如果有)
+ current_user_id = session.get('user_id') if 'user_id' in session else None
+
+ # 构建响应数据
+ result = []
+ for user in followers:
+ # 检查当前用户是否关注了这个粉丝
+ is_following = False
+ if current_user_id:
+ follow_relation = Follow.query.filter_by(
+ follower_id=current_user_id,
+ followee_id=user.id
+ ).first()
+ is_following = follow_relation is not None
+
+ # 计算该粉丝的粉丝数
+ followers_count = Follow.query.filter_by(followee_id=user.id).count()
+
+ result.append({
+ 'id': user.id,
+ 'username': user.username,
+ 'avatar': user.avatar,
+ 'bio': user.bio,
+ 'followers_count': followers_count,
+ 'is_following': is_following
+ })
+
+
+ return jsonify({
+ 'success': True,
+ 'data': result
+ })
+
+ except Exception as e:
+ app.logger.error(f"获取粉丝列表失败: {str(e)}")
+ return jsonify({
+ 'success': False,
+ 'error': '获取粉丝列表失败'
+ }), 500
+
+# 辅助函数:检查当前用户是否关注了目标用户
+def check_following_status(follower_id, followee_id):
+ return Follow.query.filter_by(
+ follower_id=follower_id,
+ followee_id=followee_id
+ ).first() is not None
+
+
+# 记录用户点赞收藏总数
+@app.route('/api/user/<int:user_id>/interactions', methods=['GET'])
+def get_user_interactions(user_id):
+ try:
+ # 计算用户的获赞总数(所有帖子的点赞数)
+ like_count = db.session.query(db.func.sum(Behavior.value)).filter(
+ Behavior.post.has(user_id=user_id),
+ Behavior.type == 'like'
+ ).scalar() or 0
+
+ # 计算用户的收藏总数(所有帖子的收藏数)
+ favorite_count = db.session.query(db.func.sum(Behavior.value)).filter(
+ Behavior.post.has(user_id=user_id),
+ Behavior.type == 'favorite'
+ ).scalar() or 0
+
+ return jsonify({
+ 'likes_count': like_count,
+ 'favorites_count': favorite_count
+ })
+
+ except Exception as e:
+ app.logger.error(f"获取用户互动数据失败: {str(e)}")
+ return jsonify({'error': '获取互动数据失败'}), 500
+
+
+if __name__ == '__main__':
+ app.run(debug=True)
\ No newline at end of file