blob: 0e10b68396ea659b391cc55b9873cb93eabc370a [file] [log] [blame]
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='更新时间')
birthday = db.Column(db.TIMESTAMP, server_default=db.func.current_timestamp(),comment='生日')
gender = db.Column(db.String(10),comment='性别')
location = db.Column(db.String(100),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,
'gender': user.gender,
'location': user.location,
'birthday': user.birthday
})
# 更新用户信息
@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
print(data)
if 'avatar' in data:
user.avatar = data['avatar']
if 'bio' in data:
user.bio = data['bio']
if 'gender' in data:
user.gender = data['gender']
if 'location' in data:
user.location = data['location']
if 'birthday' in data:
user.birthday = data['birthday']
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.user_id==user_id,
Behavior.type == 'like'
).scalar() or 0
# 计算用户的收藏总数(所有帖子的收藏数)
favorite_count = db.session.query(db.func.sum(Behavior.value)).filter(
Behavior.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,port='5715',host='0.0.0.0')